Fix support for local jars in library projects.
Xavier Ducrohet [Fri, 15 Mar 2013 01:37:18 +0000 (18:37 -0700)]
Change-Id: If19406b935965bde63a761236366137f6fb5d73f

45 files changed:
.gitignore
builder/src/main/java/com/android/builder/AndroidBuilder.java
builder/src/main/java/com/android/builder/AndroidDependency.java
builder/src/main/java/com/android/builder/BundleDependency.java
builder/src/main/java/com/android/builder/DependencyContainer.java [new file with mode: 0644]
builder/src/main/java/com/android/builder/JarDependency.java
builder/src/main/java/com/android/builder/ManifestDependency.java
builder/src/main/java/com/android/builder/ManifestProvider.java
builder/src/main/java/com/android/builder/SymbolFileProvider.java
builder/src/main/java/com/android/builder/VariantConfiguration.java
builder/src/main/java/com/android/builder/compiling/DependencyFileProcessor.java
builder/src/main/java/com/android/builder/internal/incremental/DependencyData.java
builder/src/test/java/com/android/builder/VariantConfigurationTest.java
builder/src/test/java/com/android/builder/signing/KeyStoreHelperTest.java
changelog.txt
gradle/src/build-test/groovy/com/android/build/gradle/AutomatedBuildTest.java
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/LibraryPlugin.groovy
gradle/src/main/groovy/com/android/build/gradle/internal/dependency/AndroidDependencyImpl.groovy [deleted file]
gradle/src/main/groovy/com/android/build/gradle/internal/dependency/AndroidDependencyImpl.java [new file with mode: 0644]
gradle/src/main/groovy/com/android/build/gradle/internal/dependency/ConfigurationDependencies.groovy
gradle/src/main/groovy/com/android/build/gradle/internal/tasks/DependencyBasedCompileTask.groovy
tests/localJars/app/build.gradle [new file with mode: 0644]
tests/localJars/app/src/main/AndroidManifest.xml [new file with mode: 0644]
tests/localJars/app/src/main/java/com/example/android/multiproject/MainActivity.java [new file with mode: 0644]
tests/localJars/app/src/main/res/drawable-hdpi/ic_launcher.png [new file with mode: 0644]
tests/localJars/app/src/main/res/drawable-ldpi/ic_launcher.png [new file with mode: 0644]
tests/localJars/app/src/main/res/drawable-mdpi/ic_launcher.png [new file with mode: 0644]
tests/localJars/app/src/main/res/drawable-xhdpi/ic_launcher.png [new file with mode: 0644]
tests/localJars/app/src/main/res/layout/main.xml [new file with mode: 0644]
tests/localJars/app/src/main/res/values/strings.xml [new file with mode: 0644]
tests/localJars/baseLibrary/build.gradle [new file with mode: 0644]
tests/localJars/baseLibrary/libs/util-1.0.jar [new file with mode: 0644]
tests/localJars/baseLibrary/src/main/AndroidManifest.xml [new file with mode: 0644]
tests/localJars/baseLibrary/src/main/java/com/sample/android/multiproject/library/PersonView.java [new file with mode: 0644]
tests/localJars/build.gradle [new file with mode: 0644]
tests/localJars/library/build.gradle [new file with mode: 0644]
tests/localJars/library/src/main/AndroidManifest.xml [new file with mode: 0644]
tests/localJars/library/src/main/java/com/example/android/multiproject/library/ShowPeopleActivity.java [new file with mode: 0644]
tests/localJars/library/src/main/res/values/strings.xml [new file with mode: 0644]
tests/localJars/settings.gradle [new file with mode: 0644]
tests/localJars/util/build.gradle [new file with mode: 0644]
tests/localJars/util/src/main/java/com/example/android/multiproject/person/People.java [new file with mode: 0644]
tests/localJars/util/src/main/java/com/example/android/multiproject/person/Person.java [new file with mode: 0644]

index ff1178c..1d29ef7 100644 (file)
@@ -14,6 +14,7 @@ tests/flavorlib/*/build
 tests/flavorlibWithFailedTests/*/build
 tests/libsTest/*/build
 tests/multiproject/*/build
+tests/localJars/*/build
 tests/renderscriptInLib/*/build
 tests/repo/*/build
 tests/tictactoe/*/build
index c7a6751..5379077 100644 (file)
@@ -92,7 +92,7 @@ public class AndroidBuilder {
 
     private static final DependencyFileProcessor sNoOpDependencyFileProcessor = new DependencyFileProcessor() {
         @Override
-        public boolean processFile(File dependencyFile) {
+        public boolean processFile(@NonNull File dependencyFile) {
             return true;
         }
     };
index 07f13a4..a3ce2ae 100644 (file)
@@ -16,6 +16,8 @@
 
 package com.android.builder;
 
+import com.android.annotations.NonNull;
+
 import java.io.File;
 import java.util.List;
 
@@ -27,51 +29,83 @@ public interface AndroidDependency extends ManifestDependency, SymbolFileProvide
     /**
      * Returns the location of the unarchived bundle.
      */
+    @NonNull
     File getFolder();
 
     /**
      * Returns the direct dependency of this dependency.
      */
+    @NonNull
     List<AndroidDependency> getDependencies();
 
     /**
      * Returns the location of the jar file to use for packaging.
-     * Cannot be null.
+     *
+     * @return a File for the jar file. The file may not point to an existing file.
      */
+    @NonNull
     File getJarFile();
 
     /**
+     * Returns the list of local Jar files that are included in the dependency.
+     * @return a list of JarDependency. May be empty but not null.
+     */
+    @NonNull
+    List<JarDependency> getLocalDependencies();
+
+    /**
      * Returns the location of the res folder.
+     *
+     * @return a File for the res folder. The file may not point to an existing folder.
      */
+    @NonNull
     File getResFolder();
 
     /**
      * Returns the location of the assets folder.
+     *
+     * @return a File for the assets folder. The file may not point to an existing folder.
      */
+    @NonNull
     File getAssetsFolder();
 
     /**
      * Returns the location of the jni libraries folder.
+     *
+     * @return a File for the folder. The file may not point to an existing folder.
      */
+    @NonNull
     File getJniFolder();
 
     /**
      * Returns the location of the aidl import folder.
+     *
+     * @return a File for the folder. The file may not point to an existing folder.
      */
+    @NonNull
     File getAidlFolder();
 
     /**
      * Returns the location of the renderscript import folder.
+     *
+     * @return a File for the folder. The file may not point to an existing folder.
      */
+    @NonNull
     File getRenderscriptFolder();
 
     /**
      * Returns the location of the proguard files.
+     *
+     * @return a File for the file. The file may not point to an existing file.
      */
+    @NonNull
     File getProguardRules();
 
     /**
      * Returns the location of the lint jar.
+     *
+     * @return a File for the jar file. The file may not point to an existing file.
      */
+    @NonNull
     File getLintJar();
 }
index d65c390..1e61cd6 100644 (file)
@@ -20,8 +20,10 @@ import com.android.SdkConstants;
 import com.android.annotations.NonNull;
 import com.android.annotations.Nullable;
 import com.google.common.base.Objects;
+import com.google.common.collect.Lists;
 
 import java.io.File;
+import java.util.List;
 
 /**
  * Default implementation of the AndroidDependency interface that handles a default bundle project
@@ -31,6 +33,7 @@ public abstract class BundleDependency implements AndroidDependency {
 
     private final String mName;
     private final File mBundleFolder;
+    private List<JarDependency> mLocalDependencies;
 
     /**
      * Creates the bundle dependency with an optional name
@@ -56,60 +59,93 @@ public abstract class BundleDependency implements AndroidDependency {
     }
 
     @Override
+    @NonNull
     public File getManifest() {
         return new File(mBundleFolder, SdkConstants.FN_ANDROID_MANIFEST_XML);
     }
 
     @Override
+    @NonNull
     public File getSymbolFile() {
         return new File(mBundleFolder, "R.txt");
     }
 
     @Override
+    @NonNull
     public File getFolder() {
         return mBundleFolder;
     }
 
     @Override
+    @NonNull
     public File getJarFile() {
         return new File(mBundleFolder, SdkConstants.FN_CLASSES_JAR);
     }
 
     @Override
+    @NonNull
+    public List<JarDependency> getLocalDependencies() {
+        synchronized (this) {
+            if (mLocalDependencies == null) {
+                mLocalDependencies = Lists.newArrayList();
+                File[] jarList = new File(mBundleFolder, SdkConstants.LIBS_FOLDER).listFiles();
+                if (jarList != null) {
+                    for (File jars : jarList) {
+                        if (jars.isFile() && jars.getName().endsWith(".jar")) {
+                            mLocalDependencies.add(new JarDependency(jars));
+                        }
+                    }
+                }
+            }
+
+            return mLocalDependencies;
+        }
+    }
+
+
+    @Override
+    @NonNull
     public File getResFolder() {
         return new File(mBundleFolder, SdkConstants.FD_RES);
     }
 
     @Override
+    @NonNull
     public File getAssetsFolder() {
         return new File(mBundleFolder, SdkConstants.FD_ASSETS);
     }
 
     @Override
+    @NonNull
     public File getJniFolder() {
         return new File(mBundleFolder, "jni");
     }
 
     @Override
+    @NonNull
     public File getAidlFolder() {
         return new File(mBundleFolder, SdkConstants.FD_AIDL);
     }
 
     @Override
+    @NonNull
     public File getRenderscriptFolder() {
         return new File(mBundleFolder, SdkConstants.FD_RENDERSCRIPT);
     }
 
     @Override
+    @NonNull
     public File getProguardRules() {
         return new File(mBundleFolder, "proguard.txt");
     }
 
     @Override
+    @NonNull
     public File getLintJar() {
         return new File(mBundleFolder, "lint.jar");
     }
 
+    @NonNull
     public File getBundleFolder() {
         return mBundleFolder;
     }
diff --git a/builder/src/main/java/com/android/builder/DependencyContainer.java b/builder/src/main/java/com/android/builder/DependencyContainer.java
new file mode 100644 (file)
index 0000000..8ad9845
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2013 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.builder;
+
+import com.android.annotations.NonNull;
+
+import java.util.List;
+
+/**
+ * An object able to provide the three types of dependencies an Android project can have:
+ * - local jar dependencies
+ * - artifact jar dependencies
+ * - android library dependencies
+ */
+public interface DependencyContainer {
+
+    /**
+     * Returns a list top level dependency. Each library object should contain
+     * its own dependencies. This is actually a dependency graph.
+     *
+     * @return a non null (but possibly empty) list.
+     */
+    @NonNull
+    List<? extends AndroidDependency> getAndroidDependencies();
+
+    @NonNull
+    List<JarDependency> getJarDependencies();
+
+    @NonNull
+    List<JarDependency> getLocalDependencies();
+}
index 91f71d8..46ac01b 100644 (file)
 
 package com.android.builder;
 
+import com.android.annotations.NonNull;
+
+import java.io.File;
+
 /**
  * Represents a Jar dependency. This could be the output of a Java project.
  */
 public class JarDependency {
 
-    private String mLocation;
+    private final File mJarFile;
     private final boolean mCompiled;
     private final boolean mPackaged;
     private final boolean mProguarded;
 
-    public JarDependency(String location, boolean compiled, boolean packaged, boolean proguarded) {
-        mLocation = location;
+    public JarDependency(@NonNull File jarFile, boolean compiled, boolean packaged,
+                         boolean proguarded) {
+        mJarFile = jarFile;
         mCompiled = compiled;
         mPackaged = packaged;
         mProguarded = proguarded;
     }
 
-    public String getLocation() {
-        return mLocation;
+    public JarDependency(@NonNull File jarFile) {
+        this(jarFile, true, true, true);
+    }
+
+    @NonNull
+    public File getJarFile() {
+        return mJarFile;
     }
 
     public boolean isCompiled() {
index 6f3bfdd..805fd27 100644 (file)
@@ -16,6 +16,8 @@
 
 package com.android.builder;
 
+import com.android.annotations.NonNull;
+
 import java.util.List;
 
 /**
@@ -26,5 +28,6 @@ public interface ManifestDependency extends ManifestProvider {
     /**
      * Returns the direct dependency of this dependency.
      */
+    @NonNull
     List<? extends ManifestDependency> getManifestDependencies();
 }
index 214f42e..eb05e1c 100644 (file)
@@ -16,6 +16,8 @@
 
 package com.android.builder;
 
+import com.android.annotations.NonNull;
+
 import java.io.File;
 
 /**
@@ -26,5 +28,6 @@ public interface ManifestProvider {
     /**
      * Returns the location of the manifest.
      */
+    @NonNull
     File getManifest();
 }
index 59241a4..55d4b32 100644 (file)
@@ -16,6 +16,8 @@
 
 package com.android.builder;
 
+import com.android.annotations.NonNull;
+
 import java.io.File;
 
 /**
@@ -26,5 +28,6 @@ public interface SymbolFileProvider extends ManifestProvider {
     /**
      * Returns the location of the text symbol file
      */
+    @NonNull
     File getSymbolFile();
 }
index 84bbaa5..77523b1 100644 (file)
@@ -53,6 +53,7 @@ public class VariantConfiguration {
     private final Type mType;
     /** Optional tested config in case type is Type#TEST */
     private final VariantConfiguration mTestedConfig;
+    private final String mDebugName;
     /** An optional output that is only valid if the type is Type#LIBRARY so that the test
      * for the library can use the library as if it was a normal dependency. */
     private AndroidDependency mOutput;
@@ -92,13 +93,16 @@ public class VariantConfiguration {
      * @param defaultSourceProvider the default source provider. Required
      * @param buildType the build type for this variant. Required.
      * @param buildTypeSourceProvider the source provider for the build type. Required.
+     * @param debugName an optional debug name
      */
     public VariantConfiguration(
             @NonNull ProductFlavor defaultConfig, @NonNull SourceProvider defaultSourceProvider,
-            @NonNull BuildType buildType, @NonNull SourceProvider buildTypeSourceProvider) {
+            @NonNull BuildType buildType, @NonNull SourceProvider buildTypeSourceProvider,
+            @Nullable String debugName) {
         this(defaultConfig, defaultSourceProvider,
                 buildType, buildTypeSourceProvider,
-                Type.DEFAULT, null /*testedConfig*/);
+                Type.DEFAULT, null /*testedConfig*/,
+                debugName);
     }
 
     /**
@@ -109,14 +113,16 @@ public class VariantConfiguration {
      * @param buildType the build type for this variant. Required.
      * @param buildTypeSourceProvider the source provider for the build type. Required.
      * @param type the type of the project.
+     * @param debugName an optional debug name
      */
     public VariantConfiguration(
             @NonNull ProductFlavor defaultConfig, @NonNull SourceProvider defaultSourceProvider,
             @NonNull BuildType buildType, @NonNull SourceProvider buildTypeSourceProvider,
-            @NonNull Type type) {
+            @NonNull Type type, @Nullable String debugName) {
         this(defaultConfig, defaultSourceProvider,
                 buildType, buildTypeSourceProvider,
-                type, null /*testedConfig*/);
+                type, null /*testedConfig*/,
+                debugName);
     }
 
     /**
@@ -128,17 +134,20 @@ public class VariantConfiguration {
      * @param buildTypeSourceProvider the source provider for the build type. Required.
      * @param type the type of the project.
      * @param testedConfig the reference to the tested project. Required if type is Type.TEST
+     * @param debugName an optional debug name
      */
     public VariantConfiguration(
             @NonNull ProductFlavor defaultConfig, @NonNull SourceProvider defaultSourceProvider,
             @NonNull BuildType buildType, SourceProvider buildTypeSourceProvider,
-            @NonNull Type type, @Nullable VariantConfiguration testedConfig) {
+            @NonNull Type type, @Nullable VariantConfiguration testedConfig,
+            @Nullable String debugName) {
         mDefaultConfig = checkNotNull(defaultConfig);
         mDefaultSourceProvider = checkNotNull(defaultSourceProvider);
         mBuildType = checkNotNull(buildType);
         mBuildTypeSourceProvider = buildTypeSourceProvider;
         mType = checkNotNull(type);
         mTestedConfig = testedConfig;
+        mDebugName = debugName;
         checkState(mType != Type.TEST || mTestedConfig != null);
 
         mMergedFlavor = mDefaultConfig;
@@ -162,6 +171,7 @@ public class VariantConfiguration {
      * @param sourceProvider the configured product flavor
      * @return the config object
      */
+    @NonNull
     public VariantConfiguration addProductFlavor(@NonNull ProductFlavor productFlavor,
                                                  @NonNull SourceProvider sourceProvider) {
         mFlavorConfigs.add(productFlavor);
@@ -172,14 +182,25 @@ public class VariantConfiguration {
     }
 
     /**
-     * Sets the library dependencies.
+     * Sets the dependencies
      *
-     * @param jars list of jar dependency. This should include the jar dependencies of Android
-     *             projects.
+     * @param containers a list of DependencyContainer.
      * @return the config object
      */
-    public VariantConfiguration setJarDependencies(List<JarDependency> jars) {
-        mJars.addAll(jars);
+    @NonNull
+    public VariantConfiguration setDependencies(
+            @NonNull List<? extends DependencyContainer> containers) {
+
+        for (DependencyContainer container : containers) {
+            mDirectLibraries.addAll(container.getAndroidDependencies());
+            mJars.addAll(container.getJarDependencies());
+            mJars.addAll(container.getLocalDependencies());
+        }
+        resolveIndirectLibraryDependencies(mDirectLibraries, mFlatLibraries);
+
+        for (AndroidDependency androidDependency : mFlatLibraries) {
+            mJars.addAll(androidDependency.getLocalDependencies());
+        }
         return this;
     }
 
@@ -187,28 +208,12 @@ public class VariantConfiguration {
      * Returns the list of jar dependencies
      * @return a non null collection of Jar dependencies.
      */
+    @NonNull
     public Collection<JarDependency> getJars() {
         return mJars;
     }
 
     /**
-     * Set the Library Project dependencies.
-     * @param directLibraries list of direct dependencies. Each library object should contain
-     *            its own dependencies. This is actually a dependency graph.
-     * @return the config object
-     */
-    public VariantConfiguration setAndroidDependencies(
-            @NonNull List<AndroidDependency> directLibraries) {
-        if (directLibraries != null) {
-            mDirectLibraries.addAll(directLibraries);
-        }
-
-        resolveIndirectLibraryDependencies(mDirectLibraries, mFlatLibraries);
-
-        return this;
-    }
-
-    /**
      * Sets the output of this variant. This is required when the variant is a library so that
      * the variant that tests this library can properly include the tested library in its own
      * package.
@@ -217,23 +222,28 @@ public class VariantConfiguration {
      *               location of all the created items.
      * @return the config object
      */
+    @NonNull
     public VariantConfiguration setOutput(AndroidDependency output) {
         mOutput = output;
         return this;
     }
 
+    @NonNull
     public ProductFlavor getDefaultConfig() {
         return mDefaultConfig;
     }
 
+    @NonNull
     public SourceProvider getDefaultSourceSet() {
         return mDefaultSourceProvider;
     }
 
+    @NonNull
     public ProductFlavor getMergedFlavor() {
         return mMergedFlavor;
     }
 
+    @NonNull
     public BuildType getBuildType() {
         return mBuildType;
     }
@@ -241,6 +251,7 @@ public class VariantConfiguration {
     /**
      * The SourceProvider for the BuildType. Can be null.
      */
+    @Nullable
     public SourceProvider getBuildTypeSourceSet() {
         return mBuildTypeSourceProvider;
     }
@@ -249,10 +260,12 @@ public class VariantConfiguration {
         return !mFlavorConfigs.isEmpty();
     }
 
+    @NonNull
     public List<ProductFlavor> getFlavorConfigs() {
         return mFlavorConfigs;
     }
 
+    @NonNull
     public Iterable<SourceProvider> getFlavorSourceSets() {
         return mFlavorSourceProviders;
     }
@@ -277,30 +290,12 @@ public class VariantConfiguration {
         return mFlatLibraries;
     }
 
-    public List<File> getPackagedJars() {
-        List<File> jars = Lists.newArrayListWithCapacity(mJars.size() + mFlatLibraries.size());
-
-        for (JarDependency jar : mJars) {
-            File jarFile = new File(jar.getLocation());
-            if (jarFile.exists()) {
-                jars.add(jarFile);
-            }
-        }
-
-        for (AndroidDependency androidDependency : mFlatLibraries) {
-            File libJar = androidDependency.getJarFile();
-            if (libJar.exists()) {
-                jars.add(libJar);
-            }
-        }
-
-        return jars;
-    }
-
+    @NonNull
     public Type getType() {
         return mType;
     }
 
+    @Nullable
     public VariantConfiguration getTestedConfig() {
         return mTestedConfig;
     }
@@ -342,6 +337,7 @@ public class VariantConfiguration {
      * configuration of the tested variant, and this call is similar to #getPackageName()
      * @return the package name
      */
+    @Nullable
     public String getOriginalPackageName() {
         if (mType == VariantConfiguration.Type.TEST) {
             return getPackageName();
@@ -355,6 +351,7 @@ public class VariantConfiguration {
      * could be overridden through the product flavors.
      * @return the package
      */
+    @Nullable
     public String getPackageName() {
         String packageName;
 
@@ -375,6 +372,7 @@ public class VariantConfiguration {
         return packageName;
     }
 
+    @Nullable
     public String getTestedPackageName() {
         if (mType == Type.TEST) {
             if (mTestedConfig.mType == Type.LIBRARY) {
@@ -392,6 +390,7 @@ public class VariantConfiguration {
      * overridden then this returns null.
      * @return the package override or null
      */
+    @Nullable
     public String getPackageOverride() {
         String packageName = mMergedFlavor.getPackageName();
         String packageSuffix = mBuildType.getPackageNameSuffix();
@@ -418,6 +417,7 @@ public class VariantConfiguration {
      *
      * @return the version name
      */
+    @Nullable
     public String getVersionName() {
         String versionName = mMergedFlavor.getVersionName();
         String versionSuffix = mBuildType.getVersionNameSuffix();
@@ -436,10 +436,11 @@ public class VariantConfiguration {
     private final static String DEFAULT_TEST_RUNNER = "android.test.InstrumentationTestRunner";
 
     /**
-     * Returns the instrumentionRunner to use to test this variant, or if the
+     * Returns the instrumentationRunner to use to test this variant, or if the
      * variant is a test, the one to use to test the tested variant.
      * @return the instrumentation test runner name
      */
+    @Nullable
     public String getInstrumentationRunner() {
         VariantConfiguration config = this;
         if (mType == Type.TEST) {
@@ -452,6 +453,7 @@ public class VariantConfiguration {
     /**
      * Reads the package name from the manifest.
      */
+    @Nullable
     public String getPackageFromManifest() {
         File manifestLocation = mDefaultSourceProvider.getManifestFile();
         return sManifestParser.getPackage(manifestLocation);
@@ -460,6 +462,7 @@ public class VariantConfiguration {
     /**
      * Reads the version name from the manifest.
      */
+    @Nullable
     public String getVersionNameFromManifest() {
         File manifestLocation = mDefaultSourceProvider.getManifestFile();
         return sManifestParser.getVersionName(manifestLocation);
@@ -486,6 +489,7 @@ public class VariantConfiguration {
         return minSdkVersion;
     }
 
+    @Nullable
     public File getMainManifest() {
         File defaultManifest = mDefaultSourceProvider.getManifestFile();
 
@@ -528,7 +532,8 @@ public class VariantConfiguration {
      *
      * @return a list ResourceSet.
      */
-    @NonNull public List<ResourceSet> getResourceSets(@Nullable File generatedResFolder) {
+    @NonNull
+    public List<ResourceSet> getResourceSets(@Nullable File generatedResFolder) {
         List<ResourceSet> resourceSets = Lists.newArrayList();
 
         // the list of dependency must be reversed to use the right overlay order.
@@ -583,7 +588,8 @@ public class VariantConfiguration {
      *
      * @return a list ResourceSet.
      */
-    @NonNull public List<AssetSet> getAssetSets() {
+    @NonNull
+    public List<AssetSet> getAssetSets() {
         List<AssetSet> assetSets = Lists.newArrayList();
 
         // the list of dependency must be reversed to use the right overlay order.
@@ -702,21 +708,57 @@ public class VariantConfiguration {
     /**
      * Returns the compile classpath for this config. If the config tests a library, this
      * will include the classpath of the tested config
+     *
+     * @return a non null, but possibly empty set.
      */
+    @NonNull
     public Set<File> getCompileClasspath() {
         Set<File> classpath = Sets.newHashSet();
 
         for (AndroidDependency lib : mFlatLibraries) {
             classpath.add(lib.getJarFile());
+            for (JarDependency jarDependency : lib.getLocalDependencies()) {
+                classpath.add(jarDependency.getJarFile());
+            }
         }
 
         for (JarDependency jar : mJars) {
-            classpath.add(new File(jar.getLocation()));
+            if (jar.isCompiled()) {
+                classpath.add(jar.getJarFile());
+            }
         }
 
         return classpath;
     }
 
+    /**
+     * Returns the list of packaged jars for this config. If the config tests a library, this
+     * will include the jars of the tested config
+     *
+     * @return a non null, but possibly empty list.
+     */
+    @NonNull
+    public List<File> getPackagedJars() {
+        List<File> jars = Lists.newArrayListWithCapacity(mJars.size() + mFlatLibraries.size());
+
+        for (JarDependency jar : mJars) {
+            File jarFile = jar.getJarFile();
+            if (jar.isPackaged() && jarFile.exists()) {
+                jars.add(jarFile);
+            }
+        }
+
+        for (AndroidDependency androidDependency : mFlatLibraries) {
+            File libJar = androidDependency.getJarFile();
+            if (libJar.exists()) {
+                jars.add(libJar);
+            }
+        }
+
+        return jars;
+    }
+
+    @NonNull
     public List<String> getBuildConfigLines() {
         List<String> fullList = Lists.newArrayList();
 
@@ -743,6 +785,7 @@ public class VariantConfiguration {
         return fullList;
     }
 
+    @Nullable
     public SigningConfig getSigningConfig() {
         SigningConfig signingConfig = mBuildType.getSigningConfig();
         if (signingConfig != null) {
index e5565e2..cc2fd35 100644 (file)
@@ -16,6 +16,8 @@
 
 package com.android.builder.compiling;
 
+import com.android.annotations.NonNull;
+
 import java.io.File;
 
 /**
@@ -32,8 +34,7 @@ import java.io.File;
  *
  * @see com.android.builder.AndroidBuilder#compileAllAidlFiles(java.util.List, java.io.File, java.util.List, DependencyFileProcessor)
  * @see com.android.builder.AndroidBuilder#compileAidlFile(java.io.File, java.io.File, java.util.List, DependencyFileProcessor)
- * @see com.android.builder.AndroidBuilder#compileAllRenderscriptFiles(java.util.List, java.util.List, java.io.File, java.io.File, int, boolean, int, DependencyFileProcessor)
- * @see com.android.builder.AndroidBuilder#compileRenderscriptFile(java.io.File, java.util.List, java.io.File, java.io.File, int, boolean, int, DependencyFileProcessor)
+ * @see com.android.builder.AndroidBuilder#compileAllRenderscriptFiles(java.util.List, java.util.List, java.io.File, java.io.File, int, boolean, int)
  */
 public interface DependencyFileProcessor {
 
@@ -42,5 +43,5 @@ public interface DependencyFileProcessor {
      * @param dependencyFile the dependency file.
      * @return true if the dependency file can be deleted by the caller.
      */
-    boolean processFile(File dependencyFile);
+    boolean processFile(@NonNull File dependencyFile);
 }
index f350c44..f14ebc1 100644 (file)
@@ -74,7 +74,8 @@ public class DependencyData {
      *
      * @param dependencyFile the dependency file
      */
-    public static DependencyData parseDependencyFile(File dependencyFile) throws IOException {
+    public static DependencyData parseDependencyFile(@NonNull File dependencyFile)
+            throws IOException {
         // first check if the dependency file is here.
         if (!dependencyFile.isFile()) {
             return null;
@@ -90,7 +91,7 @@ public class DependencyData {
     }
 
     @VisibleForTesting
-    static DependencyData processDependencyData(List<String> content) {
+    static DependencyData processDependencyData(@NonNull List<String> content) {
         // The format is technically:
         // output1 output2 [...]: dep1 dep2 [...]
         // However, the current tools generating those files guarantee that each file path
index 47dd863..5109087 100644 (file)
@@ -120,7 +120,7 @@ public class VariantConfigurationTest extends TestCase {
         VariantConfiguration variant = new VariantConfiguration(
                 mDefaultConfig, new MockSourceProvider("main"),
                 mBuildType, new MockSourceProvider("debug"),
-                VariantConfiguration.Type.DEFAULT) {
+                VariantConfiguration.Type.DEFAULT, "test") {
             // don't do validation.
             @Override
             protected void validate() {
@@ -137,7 +137,7 @@ public class VariantConfigurationTest extends TestCase {
         VariantConfiguration variant = new VariantConfiguration(
                 mDefaultConfig, new MockSourceProvider("main"),
                 mBuildType, new MockSourceProvider("debug"),
-                VariantConfiguration.Type.DEFAULT) {
+                VariantConfiguration.Type.DEFAULT, "test") {
             @Override
             public String getPackageFromManifest() {
                 return packageName;
@@ -157,7 +157,7 @@ public class VariantConfigurationTest extends TestCase {
         VariantConfiguration variant = new VariantConfiguration(
                 mDefaultConfig, new MockSourceProvider("main"),
                 mBuildType, new MockSourceProvider("debug"),
-                VariantConfiguration.Type.DEFAULT) {
+                VariantConfiguration.Type.DEFAULT, "test") {
             @Override
             public String getVersionNameFromManifest() {
                 return versionName;
index bd20b89..b889951 100755 (executable)
@@ -79,9 +79,9 @@ public class KeyStoreHelperTest extends TestCase {
         assertTrue("30 year expiration failed",
                 certificate.getNotAfter().compareTo(c.getTime()) > 0);
 
-        // however expiration date should be passed in 30 years + 1 hour
-        c.add(Calendar.HOUR, 1);
-        assertFalse("30 year and 1 hour expiration failed",
+        // however expiration date should be passed in 30 years + a few hours
+        c.add(Calendar.HOUR, 5);
+        assertFalse("30 year and few hours expiration failed",
                 certificate.getNotAfter().compareTo(c.getTime()) > 0);
     }
 
index 0345d51..8358ccb 100644 (file)
@@ -1,3 +1,9 @@
+0.4
+
+* Fixes:
+   - Fix support for subfolders in assets/
+   - Fix cases where Android Libraries have local Jars dependencies
+
 0.3
 
 * System requirements:
index 06dd9d9..2cf2814 100644 (file)
@@ -35,7 +35,7 @@ public class AutomatedBuildTest extends BuildTest {
 
     private static final String[] sBuiltProjects = new String[] {
             "aidl", "api", "applibtest", "assets", "basic", "dependencies", "flavored",
-            "flavorlib", "flavors", "libsTest", "migrated", "multiproject", "multires",
+            "flavorlib", "flavors", "libsTest", "localJars", "migrated", "multiproject", "multires",
             "overlay1", "overlay2", "renderscript", "renderscriptInLib", "renderscriptMultiSrc",
             "tictactoe"
     };
index b18ce1b..71a0f04 100644 (file)
@@ -31,9 +31,7 @@ import com.android.build.gradle.internal.tasks.AndroidReportTask
 import com.android.build.gradle.internal.tasks.AndroidTestTask
 import com.android.build.gradle.internal.test.PluginHolder
 import com.android.build.gradle.internal.test.report.ReportType
-import com.android.builder.AndroidDependency
 import com.android.builder.BuildType
-import com.android.builder.JarDependency
 import com.android.builder.VariantConfiguration
 import com.android.builder.signing.SigningConfig
 import com.google.common.collect.ArrayListMultimap
@@ -324,28 +322,19 @@ 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)
-
+            /// add the container of dependencies
             // the order of the libraries is important. In descending order:
             // build types, flavors, defaultConfig.
-            List<AndroidDependency> libs = []
-            libs.addAll(buildTypeData.libraries)
+            List<ConfigurationDependencies> configDependencies = []
+            configDependencies.add(buildTypeData)
             // no flavors, just add the default config
-            libs.addAll(defaultConfigData.libraries)
+            configDependencies.add(defaultConfigData)
 
             def variantConfig = new VariantConfiguration(
                     defaultConfigData.productFlavor, defaultConfigData.sourceSet,
-                    buildTypeData.buildType, buildTypeData.sourceSet)
+                    buildTypeData.buildType, buildTypeData.sourceSet, project.name)
 
-            variantConfig.setJarDependencies(jars)
-            variantConfig.setAndroidDependencies(libs)
+            variantConfig.setDependencies(configDependencies)
 
             ProductionAppVariant productionAppVariant = addVariant(variantConfig,
                     buildTypeData.assembleTask, configDependencies)
@@ -366,19 +355,13 @@ class AppPlugin extends com.android.build.gradle.BasePlugin implements org.gradl
         def testVariantConfig = new VariantConfiguration(
                 defaultConfigData.productFlavor, defaultConfigData.testSourceSet,
                 testData.buildType, null,
-                VariantConfiguration.Type.TEST, testedVariant.config)
+                VariantConfiguration.Type.TEST, testedVariant.config, project.name)
 
+        // dependencies for the test variant
         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)
+        testVariantConfig.setDependencies(testConfigDependencies)
 
         def testVariant = new TestAppVariant(testVariantConfig)
         variants.add(testVariant)
@@ -411,36 +394,25 @@ 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)
-
+            /// add the container of dependencies
             // the order of the libraries is important. In descending order:
             // build types, flavors, defaultConfig.
-            List<AndroidDependency> libs = []
-            libs.addAll(buildTypeData.libraries)
+            List<ConfigurationDependencies> configDependencies = []
+            configDependencies.add(buildTypeData)
 
             def variantConfig = new VariantConfiguration(
                     extension.defaultConfig, getDefaultConfigData().sourceSet,
-                    buildTypeData.buildType, buildTypeData.sourceSet)
+                    buildTypeData.buildType, buildTypeData.sourceSet, project.name)
 
             for (ProductFlavorData data : flavorDataList) {
                 variantConfig.addProductFlavor(data.productFlavor, data.sourceSet)
-                jars.addAll(data.jars)
-                libs.addAll(data.libraries)
                 configDependencies.add(data)
             }
 
             // now add the defaultConfig
-            libs.addAll(defaultConfigData.libraries)
+            configDependencies.add(defaultConfigData)
 
-            variantConfig.setJarDependencies(jars)
-            variantConfig.setAndroidDependencies(libs)
+            variantConfig.setDependencies(configDependencies)
 
             ProductionAppVariant productionAppVariant = addVariant(variantConfig, null,
                     configDependencies)
@@ -470,30 +442,22 @@ class AppPlugin extends com.android.build.gradle.BasePlugin implements org.gradl
         def testVariantConfig = new VariantConfiguration(
                 extension.defaultConfig, getDefaultConfigData().testSourceSet,
                 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)
+                VariantConfiguration.Type.TEST, testedVariant.config, project.name)
 
+        /// add the container of dependencies
         // the order of the libraries is important. In descending order:
-        // flavors, defaultConfig.
-        List<AndroidDependency> testLibs = []
+        // flavors, defaultConfig. No build type for tests
+        List<ConfigurationDependencies> testConfigDependencies = []
 
         for (ProductFlavorData data : flavorDataList) {
             testVariantConfig.addProductFlavor(data.productFlavor, data.testSourceSet)
-            testJars.addAll(data.testConfigDependencies.jars)
-            testLibs.addAll(data.testConfigDependencies.libraries)
+            testConfigDependencies.add(data.testConfigDependencies)
         }
 
         // now add the default config
-        testLibs.addAll(defaultConfigData.testConfigDependencies.libraries)
+        testConfigDependencies.add(defaultConfigData.testConfigDependencies)
 
-        testVariantConfig.setJarDependencies(testJars)
-        testVariantConfig.setAndroidDependencies(testLibs)
+        testVariantConfig.setDependencies(testConfigDependencies)
 
         def testVariant = new TestAppVariant(testVariantConfig)
         variants.add(testVariant)
index 659e2f7..65aee56 100644 (file)
@@ -903,7 +903,7 @@ public abstract class BasePlugin {
     }
 
     def resolveDependencies(List<ConfigurationDependencies> configs) {
-        Map<ModuleVersionIdentifier, List<AndroidDependency>> modules = [:]
+        Map<ModuleVersionIdentifier, List<AndroidDependencyImpl>> modules = [:]
         Map<ModuleVersionIdentifier, List<ResolvedArtifact>> artifacts = [:]
         Multimap<AndroidDependency, ConfigurationDependencies> reverseMap = ArrayListMultimap.create()
 
@@ -950,7 +950,7 @@ public abstract class BasePlugin {
 
     def resolveDependencyForConfig(
             ConfigurationDependencies configDependencies,
-            Map<ModuleVersionIdentifier, List<AndroidDependency>> modules,
+            Map<ModuleVersionIdentifier, List<AndroidDependencyImpl>> modules,
             Map<ModuleVersionIdentifier, List<ResolvedArtifact>> artifacts,
             Multimap<AndroidDependency, ConfigurationDependencies> reverseMap) {
 
@@ -963,27 +963,30 @@ public abstract class BasePlugin {
         configDependencies.checker = new DependencyChecker(configDependencies, logger)
 
         // TODO - defer downloading until required -- This is hard to do as we need the info to build the variant config.
-        List<AndroidDependency> bundles = []
+        List<AndroidDependencyImpl> bundles = []
         List<JarDependency> jars = []
+        List<JarDependency> localJars = []
         collectArtifacts(compileClasspath, artifacts)
         compileClasspath.incoming.resolutionResult.root.dependencies.each { ResolvedDependencyResult dep ->
             addDependency(dep.selected, configDependencies, bundles, jars, modules,
                     artifacts, reverseMap)
         }
+
         // also need to process local jar files, as they are not processed by the
-        // resolvedConfiguration result
+        // resolvedConfiguration result. This only includes the local jar files for this project.
         compileClasspath.allDependencies.each { dep ->
             if (dep instanceof SelfResolvingDependency &&
                     !(dep instanceof ProjectDependency)) {
                 Set<File> files = ((SelfResolvingDependency) dep).resolve()
                 for (File f : files) {
-                    jars << new JarDependency(f.absolutePath, true, true, true)
+                    localJars << new JarDependency(f)
                 }
             }
         }
 
-        configDependencies.libraries = bundles
-        configDependencies.jars = jars
+        configDependencies.addLibraries(bundles)
+        configDependencies.addJars(jars)
+        configDependencies.addLocalJars(localJars)
 
         // TODO - filter bundles out of source set classpath
 
@@ -1012,9 +1015,9 @@ public abstract class BasePlugin {
 
     def addDependency(ResolvedModuleVersionResult moduleVersion,
                       ConfigurationDependencies configDependencies,
-                      Collection<AndroidDependency> bundles,
-                      Collection<JarDependency> jars,
-                      Map<ModuleVersionIdentifier, List<AndroidDependency>> modules,
+                      Collection<AndroidDependencyImpl> bundles,
+                      List<JarDependency> jars,
+                      Map<ModuleVersionIdentifier, List<AndroidDependencyImpl>> modules,
                       Map<ModuleVersionIdentifier, List<ResolvedArtifact>> artifacts,
                       Multimap<AndroidDependency, ConfigurationDependencies> reverseMap) {
         def id = moduleVersion.id
@@ -1022,7 +1025,7 @@ public abstract class BasePlugin {
             return
         }
 
-        List<AndroidDependency> bundlesForThisModule = modules[id]
+        List<AndroidDependencyImpl> bundlesForThisModule = modules[id]
         if (bundlesForThisModule == null) {
             bundlesForThisModule = []
             modules[id] = bundlesForThisModule
@@ -1039,13 +1042,13 @@ public abstract class BasePlugin {
                     def explodedDir = project.file(
                             "$project.buildDir/exploded-bundles/$artifact.file.name")
                     AndroidDependencyImpl adep = new AndroidDependencyImpl(
-                            id.group + ":" + id.name + ":" + id.version,
-                            explodedDir, nestedBundles, artifact.file)
+                            explodedDir, nestedBundles, artifact.file,
+                            id.group + ":" + id.name + ":" + id.version)
                     bundlesForThisModule << adep
                     reverseMap.put(adep, configDependencies)
                 } else {
                     // TODO - need the correct values for the boolean flags
-                    jars << new JarDependency(artifact.file.absolutePath, true, true, true)
+                    jars << new JarDependency(artifact.file)
                 }
             }
 
@@ -1102,22 +1105,6 @@ public abstract class BasePlugin {
         return null
     }
 
-    /**
-     * TODO: remove once assets support more than one folder.
-     * @param dirs
-     * @return
-     */
-    protected static File getFirstOptionalDir(Set<File> dirs) {
-        Iterator<File> iterator = dirs.iterator();
-
-        File dir = iterator.hasNext() ? iterator.next() : null;
-        if (dir != null && dir.isDirectory()) {
-            return dir
-        }
-
-        return null
-    }
-
     protected List<ManifestDependencyImpl> getManifestDependencies(
             List<AndroidDependency> libraries) {
 
index b6b891d..6400a65 100644 (file)
@@ -24,9 +24,11 @@ import com.android.build.gradle.internal.dependency.ConfigurationDependencies
 import com.android.builder.AndroidDependency
 import com.android.builder.BuilderConstants
 import com.android.builder.BundleDependency
+import com.android.builder.DependencyContainer
 import com.android.builder.JarDependency
 import com.android.builder.ManifestDependency
 import com.android.builder.VariantConfiguration
+import com.google.common.collect.Sets
 import org.gradle.api.Plugin
 import org.gradle.api.Project
 import org.gradle.api.internal.project.ProjectInternal
@@ -132,28 +134,18 @@ public class LibraryPlugin extends BasePlugin implements Plugin<Project> {
                                                     boolean publishArtifact) {
         ProductFlavorData defaultConfigData = getDefaultConfigData();
 
+        // the order of the libraries is important. In descending order:
+        // build type, defaultConfig.
         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)
+        configDependencies.add(defaultConfigData)
 
         def variantConfig = new VariantConfiguration(
                 defaultConfigData.productFlavor, defaultConfigData.sourceSet,
                 buildTypeData.buildType, buildTypeData.sourceSet,
-                VariantConfiguration.Type.LIBRARY)
+                VariantConfiguration.Type.LIBRARY, project.name)
 
-        variantConfig.setJarDependencies(jars)
-        variantConfig.setAndroidDependencies(libs)
+        variantConfig.setDependencies(configDependencies)
 
         String packageName = variantConfig.getPackageFromManifest()
         if (packageName == null) {
@@ -217,14 +209,20 @@ public class LibraryPlugin extends BasePlugin implements Plugin<Project> {
 
         // package the renderscript header files files into the bundle folder
         Sync packageRenderscript = project.tasks.add("package${variant.name}Renderscript", Sync)
-        // packageAidl from 3 sources. the order is important to make sure the override works well.
+        // package from 3 sources. the order is important to make sure the override works well.
         packageRenderscript.from(defaultConfigData.sourceSet.renderscript.directories,
                 buildTypeData.sourceSet.renderscript.directories).include("**/*.rsh")
         packageRenderscript.into(project.file(
                 "$project.buildDir/$DIR_BUNDLES/${variant.dirName}/$SdkConstants.FD_RENDERSCRIPT"))
 
+        // package the renderscript header files files into the bundle folder
+        Sync packageLocalJar = project.tasks.add("package${variant.name}LocalJar", Sync)
+        packageLocalJar.from(getLocalJarFileList(configDependencies))
+        packageLocalJar.into(project.file(
+                "$project.buildDir/$DIR_BUNDLES/${variant.dirName}/$SdkConstants.LIBS_FOLDER"))
+
         Zip bundle = project.tasks.add("bundle${variant.name}", Zip)
-        bundle.dependsOn jar, packageAidl, packageRenderscript
+        bundle.dependsOn jar, packageAidl, packageRenderscript, packageLocalJar
         bundle.setDescription("Assembles a bundle containing the library in ${variant.name}.");
         bundle.destinationDir = project.file("$project.buildDir/libs")
         bundle.extension = BuilderConstants.EXT_LIB_ARCHIVE
@@ -263,28 +261,31 @@ public class LibraryPlugin extends BasePlugin implements Plugin<Project> {
         return variant
     }
 
-    private TestAppVariant createTestTasks(ProductionAppVariant testedVariant) {
-        ProductFlavorData defaultConfigData = getDefaultConfigData();
+    static Object[] getLocalJarFileList(List<? extends DependencyContainer> containerList) {
+        Set<File> files = Sets.newHashSet()
+        for (DependencyContainer dependencyContainer : containerList) {
+            for (JarDependency jarDependency : dependencyContainer.localDependencies) {
+                files.add(jarDependency.jarFile)
+            }
+        }
 
-        List<ConfigurationDependencies> configDependencies = []
-        configDependencies.add(defaultConfigData.testConfigDependencies)
+        return files.toArray()
+    }
 
-        // list of dependency to set on the variantConfig
-        List<JarDependency> jars = []
-        jars.addAll(defaultConfigData.testConfigDependencies.jars)
+    private TestAppVariant createTestTasks(ProductionAppVariant testedVariant) {
+        ProductFlavorData defaultConfigData = getDefaultConfigData();
 
         // the order of the libraries is important. In descending order:
         // build types, defaultConfig.
-        List<AndroidDependency> libs = []
-        libs.addAll(defaultConfigData.testConfigDependencies.libraries)
+        List<ConfigurationDependencies> configDependencies = []
+        configDependencies.add(defaultConfigData.testConfigDependencies)
 
         def testVariantConfig = new VariantConfiguration(
                 defaultConfigData.productFlavor, defaultConfigData.testSourceSet,
                 debugBuildTypeData.buildType, null,
-                VariantConfiguration.Type.TEST, testedVariant.config)
+                VariantConfiguration.Type.TEST, testedVariant.config, project.name)
 
-        testVariantConfig.setJarDependencies(jars)
-        testVariantConfig.setAndroidDependencies(libs)
+        testVariantConfig.setDependencies(configDependencies)
 
         def testVariant = new TestAppVariant(testVariantConfig,)
         variants.add(testVariant)
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/dependency/AndroidDependencyImpl.groovy b/gradle/src/main/groovy/com/android/build/gradle/internal/dependency/AndroidDependencyImpl.groovy
deleted file mode 100644 (file)
index 72853ee..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.dependency
-
-import com.android.builder.AndroidDependency
-import com.android.builder.BundleDependency
-import com.android.builder.ManifestDependency
-
-class AndroidDependencyImpl extends BundleDependency {
-    final List<AndroidDependency> dependencies;
-    final File bundle
-
-    AndroidDependencyImpl(String name, File explodedBundle, List<AndroidDependency> dependencies,
-                          File bundle) {
-        super(explodedBundle, name)
-        this.dependencies = dependencies
-        this.bundle = bundle
-    }
-
-    @Override
-    List<ManifestDependency> getManifestDependencies() {
-        return dependencies
-    }
-}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/dependency/AndroidDependencyImpl.java b/gradle/src/main/groovy/com/android/build/gradle/internal/dependency/AndroidDependencyImpl.java
new file mode 100644 (file)
index 0000000..1707aaa
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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.dependency;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.builder.AndroidDependency;
+import com.android.builder.BundleDependency;
+import com.android.builder.ManifestDependency;
+
+import java.io.File;
+import java.util.List;
+
+public class AndroidDependencyImpl extends BundleDependency {
+    final List<AndroidDependency> dependencies;
+    final File bundle;
+
+    public AndroidDependencyImpl(@NonNull File explodedBundle,
+                                 @NonNull List<AndroidDependency> dependencies,
+                                 @NonNull File bundle,
+                                 @Nullable String name) {
+        super(explodedBundle, name);
+        this.dependencies = dependencies;
+        this.bundle = bundle;
+    }
+
+    @Override
+    @NonNull
+    public List<AndroidDependency> getDependencies() {
+        return dependencies;
+    }
+
+    @Override
+    @NonNull
+    public List<? extends ManifestDependency> getManifestDependencies() {
+        return dependencies;
+    }
+}
index a982f20..b4ec45b 100644 (file)
  */
 
 package com.android.build.gradle.internal.dependency
-
 import com.android.annotations.NonNull
 import com.android.build.gradle.AndroidSourceSet
+import com.android.builder.AndroidDependency
+import com.android.builder.DependencyContainer
 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.
  */
-public class ConfigurationDependencies {
+public class ConfigurationDependencies implements DependencyContainer {
 
     public static enum ConfigType { DEFAULT, FLAVOR, BUILDTYPE }
 
@@ -45,8 +45,9 @@ public class ConfigurationDependencies {
         this.type = type
     }
 
-    List<AndroidDependencyImpl> libraries
-    List<JarDependency> jars
+    private final List<AndroidDependencyImpl> libraries = []
+    private final List<JarDependency> jars = []
+    private final List<JarDependency> localJars = []
 
     public Configuration getConfiguration() {
         return project.configurations[sourceSet.compileConfigurationName]
@@ -55,4 +56,38 @@ public class ConfigurationDependencies {
     public String getConfigBaseName() {
         return sourceSet.name
     }
+
+    void addLibraries(List<AndroidDependencyImpl> list) {
+        libraries.addAll(list)
+    }
+
+    void addJars(List<JarDependency> list) {
+        jars.addAll(list)
+    }
+
+    void addLocalJars(List<JarDependency> list) {
+        localJars.addAll(list)
+    }
+
+    List<AndroidDependencyImpl> getLibraries() {
+        return libraries
+    }
+
+    @NonNull
+    @Override
+    List<? extends AndroidDependency> getAndroidDependencies() {
+        return libraries
+    }
+
+    @NonNull
+    @Override
+    List<JarDependency> getJarDependencies() {
+        return jars
+    }
+
+    @NonNull
+    @Override
+    List<JarDependency> getLocalDependencies() {
+        return localJars
+    }
 }
index 85878c7..b4dc29a 100644 (file)
@@ -16,6 +16,7 @@
 
 package com.android.build.gradle.internal.tasks
 
+import com.android.annotations.NonNull
 import com.android.builder.compiling.DependencyFileProcessor
 import com.android.builder.internal.incremental.DependencyData
 import com.android.builder.internal.incremental.DependencyDataStore
@@ -50,7 +51,7 @@ public abstract class DependencyBasedCompileTask extends IncrementalTask {
         }
 
         @Override
-        boolean processFile(File dependencyFile) {
+        boolean processFile(@NonNull File dependencyFile) {
             DependencyData data = DependencyData.parseDependencyFile(dependencyFile)
             if (data != null) {
                 dependencyDataList.add(data)
diff --git a/tests/localJars/app/build.gradle b/tests/localJars/app/build.gradle
new file mode 100644 (file)
index 0000000..75b4b6c
--- /dev/null
@@ -0,0 +1,14 @@
+//
+// A basic Android application split over a couple of Gradle projects.
+//
+
+apply plugin: 'android'
+
+android {
+    compileSdkVersion 15
+//    buildToolsVersion "1.0"
+}
+
+dependencies {
+    compile project(':library')
+}
diff --git a/tests/localJars/app/src/main/AndroidManifest.xml b/tests/localJars/app/src/main/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..71e7a47
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="com.example.android.multiproject"
+      android:versionCode="1"
+      android:versionName="1.0">
+    <application android:label="@string/app_name" android:icon="@drawable/ic_launcher">
+        <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>
diff --git a/tests/localJars/app/src/main/java/com/example/android/multiproject/MainActivity.java b/tests/localJars/app/src/main/java/com/example/android/multiproject/MainActivity.java
new file mode 100644 (file)
index 0000000..11d7c32
--- /dev/null
@@ -0,0 +1,21 @@
+package com.example.android.multiproject;
+
+import android.app.Activity;
+import android.view.View;
+import android.content.Intent;
+import android.os.Bundle;
+
+import com.example.android.multiproject.library.ShowPeopleActivity;
+
+public class MainActivity extends Activity {
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+    }
+
+    public void sendMessage(View view) {
+        Intent intent = new Intent(this, ShowPeopleActivity.class);
+        startActivity(intent);
+    }
+}
diff --git a/tests/localJars/app/src/main/res/drawable-hdpi/ic_launcher.png b/tests/localJars/app/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..96a442e
Binary files /dev/null and b/tests/localJars/app/src/main/res/drawable-hdpi/ic_launcher.png differ
diff --git a/tests/localJars/app/src/main/res/drawable-ldpi/ic_launcher.png b/tests/localJars/app/src/main/res/drawable-ldpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..9923872
Binary files /dev/null and b/tests/localJars/app/src/main/res/drawable-ldpi/ic_launcher.png differ
diff --git a/tests/localJars/app/src/main/res/drawable-mdpi/ic_launcher.png b/tests/localJars/app/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..359047d
Binary files /dev/null and b/tests/localJars/app/src/main/res/drawable-mdpi/ic_launcher.png differ
diff --git a/tests/localJars/app/src/main/res/drawable-xhdpi/ic_launcher.png b/tests/localJars/app/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..71c6d76
Binary files /dev/null and b/tests/localJars/app/src/main/res/drawable-xhdpi/ic_launcher.png differ
diff --git a/tests/localJars/app/src/main/res/layout/main.xml b/tests/localJars/app/src/main/res/layout/main.xml
new file mode 100644 (file)
index 0000000..ccc59fb
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    >
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/button_send"
+            android:onClick="sendMessage" />
+</LinearLayout>
diff --git a/tests/localJars/app/src/main/res/values/strings.xml b/tests/localJars/app/src/main/res/values/strings.xml
new file mode 100644 (file)
index 0000000..e1f49b6
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="app_name">Composite App</string>
+    <string name="button_send">Go</string>
+</resources>
diff --git a/tests/localJars/baseLibrary/build.gradle b/tests/localJars/baseLibrary/build.gradle
new file mode 100644 (file)
index 0000000..4700d90
--- /dev/null
@@ -0,0 +1,11 @@
+apply plugin: 'android-library'
+
+android {
+    compileSdkVersion 15
+//    buildToolsVersion "1.0"
+}
+
+dependencies {
+    compile fileTree(dir: 'libs', include: '*.jar')
+    compile 'com.google.guava:guava:11.0.2'
+}
diff --git a/tests/localJars/baseLibrary/libs/util-1.0.jar b/tests/localJars/baseLibrary/libs/util-1.0.jar
new file mode 100644 (file)
index 0000000..55471dc
Binary files /dev/null and b/tests/localJars/baseLibrary/libs/util-1.0.jar differ
diff --git a/tests/localJars/baseLibrary/src/main/AndroidManifest.xml b/tests/localJars/baseLibrary/src/main/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..54d079c
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="com.example.android.multiproject.library.base">
+</manifest>
diff --git a/tests/localJars/baseLibrary/src/main/java/com/sample/android/multiproject/library/PersonView.java b/tests/localJars/baseLibrary/src/main/java/com/sample/android/multiproject/library/PersonView.java
new file mode 100644 (file)
index 0000000..b218532
--- /dev/null
@@ -0,0 +1,13 @@
+package com.example.android.multiproject.library;
+
+import android.widget.TextView;
+import android.content.Context;
+import com.example.android.multiproject.person.Person;
+
+class PersonView extends TextView {
+    public PersonView(Context context, Person person) {
+        super(context);
+        setTextSize(20);
+        setText(person.getName());
+    }
+}
diff --git a/tests/localJars/build.gradle b/tests/localJars/build.gradle
new file mode 100644 (file)
index 0000000..cef83b9
--- /dev/null
@@ -0,0 +1,18 @@
+buildscript {
+    repositories {
+        maven { url '../../repo' }
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:0.4-SNAPSHOT'
+    }
+}
+
+allprojects {
+    version = '1.0'
+
+    repositories {
+        mavenCentral()
+    }
+}
+
+apply plugin: 'android-reporting'
\ No newline at end of file
diff --git a/tests/localJars/library/build.gradle b/tests/localJars/library/build.gradle
new file mode 100644 (file)
index 0000000..6d07c6a
--- /dev/null
@@ -0,0 +1,10 @@
+apply plugin: 'android-library'
+
+android {
+    compileSdkVersion 15
+//    buildToolsVersion "1.0"
+}
+
+dependencies {
+    compile project(':baseLibrary')
+}
diff --git a/tests/localJars/library/src/main/AndroidManifest.xml b/tests/localJars/library/src/main/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..2bc9331
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="com.example.android.multiproject.library">
+    <application>
+        <activity
+                android:name="ShowPeopleActivity"
+                android:label="@string/title_activity_display_message" >
+            </activity>
+    </application>
+</manifest>
diff --git a/tests/localJars/library/src/main/java/com/example/android/multiproject/library/ShowPeopleActivity.java b/tests/localJars/library/src/main/java/com/example/android/multiproject/library/ShowPeopleActivity.java
new file mode 100644 (file)
index 0000000..a3f2195
--- /dev/null
@@ -0,0 +1,30 @@
+package com.example.android.multiproject.library;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.content.Intent;
+import android.widget.TextView;
+import android.widget.LinearLayout;
+
+import java.lang.String;
+import java.util.Arrays;
+
+import com.example.android.multiproject.person.Person;
+import com.example.android.multiproject.person.People;
+
+public class ShowPeopleActivity extends Activity {
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        LinearLayout group = new LinearLayout(this);
+        group.setOrientation(LinearLayout.VERTICAL);
+
+        Iterable<Person> people = new People();
+        for (Person person : people) {
+            group.addView(new PersonView(this, person));
+        }
+
+        setContentView(group);
+    }
+}
diff --git a/tests/localJars/library/src/main/res/values/strings.xml b/tests/localJars/library/src/main/res/values/strings.xml
new file mode 100644 (file)
index 0000000..45e9dbb
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="title_activity_display_message">People</string>
+</resources>
diff --git a/tests/localJars/settings.gradle b/tests/localJars/settings.gradle
new file mode 100644 (file)
index 0000000..1b43700
--- /dev/null
@@ -0,0 +1,3 @@
+include 'app'
+include 'library'
+include 'baseLibrary'
diff --git a/tests/localJars/util/build.gradle b/tests/localJars/util/build.gradle
new file mode 100644 (file)
index 0000000..dff7725
--- /dev/null
@@ -0,0 +1,8 @@
+apply plugin: 'java'
+
+dependencies {
+    compile 'com.google.guava:guava:11.0.2'
+}
+
+sourceCompatibility = "1.6"
+targetCompatibility = "1.6"
diff --git a/tests/localJars/util/src/main/java/com/example/android/multiproject/person/People.java b/tests/localJars/util/src/main/java/com/example/android/multiproject/person/People.java
new file mode 100644 (file)
index 0000000..8b99248
--- /dev/null
@@ -0,0 +1,10 @@
+package com.example.android.multiproject.person;
+
+import java.util.Iterator;
+import com.google.common.collect.Lists;
+
+public class People implements Iterable<Person> {
+    public Iterator<Person> iterator() {
+        return Lists.newArrayList(new Person("Fred"), new Person("Barney")).iterator();
+    }
+}
diff --git a/tests/localJars/util/src/main/java/com/example/android/multiproject/person/Person.java b/tests/localJars/util/src/main/java/com/example/android/multiproject/person/Person.java
new file mode 100644 (file)
index 0000000..2f4aa9f
--- /dev/null
@@ -0,0 +1,13 @@
+package com.example.android.multiproject.person;
+
+public class Person {
+    private final String name;
+
+    public Person(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+}