Merge "Improved BuildConfig."
diff --git a/builder-model/src/main/java/com/android/builder/model/BaseConfig.java b/builder-model/src/main/java/com/android/builder/model/BaseConfig.java
index fbf6eb4..713b344 100644
--- a/builder-model/src/main/java/com/android/builder/model/BaseConfig.java
+++ b/builder-model/src/main/java/com/android/builder/model/BaseConfig.java
@@ -27,11 +27,11 @@
 public interface BaseConfig {
 
     /**
-     * List of Build Config lines.
-     * @return a non-null list of lines (possibly empty)
+     * List of Build Config Fields
+     * @return a non-null list of class fields (possibly empty)
      */
     @NonNull
-    List<String> getBuildConfig();
+    List<ClassField> getBuildConfigFields();
 
     /**
      * Returns the list of proguard rule files.
diff --git a/builder-model/src/main/java/com/android/builder/model/ClassField.java b/builder-model/src/main/java/com/android/builder/model/ClassField.java
new file mode 100644
index 0000000..d6b6a26
--- /dev/null
+++ b/builder-model/src/main/java/com/android/builder/model/ClassField.java
@@ -0,0 +1,33 @@
+/*
+ * 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.model;
+
+import com.android.annotations.NonNull;
+
+/**
+ * A Simple class field with name, type and value, all as strings.
+ */
+public interface ClassField {
+    @NonNull
+    String getType();
+
+    @NonNull
+    String getName();
+
+    @NonNull
+    String getValue();
+}
diff --git a/builder/build.gradle b/builder/build.gradle
index a9f1bbe..c765b0d 100644
--- a/builder/build.gradle
+++ b/builder/build.gradle
@@ -15,6 +15,7 @@
     compile "com.android.tools.build:manifest-merger:$project.ext.baseAndroidVersion"
     compile "com.android.tools.ddms:ddmlib:$project.ext.baseAndroidVersion"
 
+    compile 'com.squareup:javawriter:2.2.1'
     compile 'org.bouncycastle:bcpkix-jdk15on:1.48'
 
     testCompile 'junit:junit:3.8.1'
diff --git a/builder/src/main/java/com/android/builder/AndroidBuilder.java b/builder/src/main/java/com/android/builder/AndroidBuilder.java
index feaa7c8..24ff0c8 100644
--- a/builder/src/main/java/com/android/builder/AndroidBuilder.java
+++ b/builder/src/main/java/com/android/builder/AndroidBuilder.java
@@ -22,7 +22,7 @@
 import com.android.builder.compiling.DependencyFileProcessor;
 import com.android.builder.dependency.ManifestDependency;
 import com.android.builder.dependency.SymbolFileProvider;
-import com.android.builder.internal.BuildConfigGenerator;
+import com.android.builder.internal.ClassFieldImpl;
 import com.android.builder.internal.SymbolLoader;
 import com.android.builder.internal.SymbolWriter;
 import com.android.builder.internal.TestManifestGenerator;
@@ -33,6 +33,7 @@
 import com.android.builder.internal.packaging.JavaResourceProcessor;
 import com.android.builder.internal.packaging.Packager;
 import com.android.builder.model.AaptOptions;
+import com.android.builder.model.ClassField;
 import com.android.builder.model.ProductFlavor;
 import com.android.builder.model.SigningConfig;
 import com.android.builder.packaging.DuplicateFileException;
@@ -80,7 +81,6 @@
  * create a builder with {@link #AndroidBuilder(SdkParser, String, ILogger, boolean)}
  *
  * then build steps can be done with
- * {@link #generateBuildConfig(String, boolean, java.util.List, String)}
  * {@link #processManifest(java.io.File, java.util.List, java.util.List, String, int, String, int, int, String)}
  * {@link #processTestManifest(String, int, int, String, String, Boolean, Boolean, java.util.List, String)}
  * {@link #processResources(java.io.File, java.io.File, java.io.File, java.util.List, String, String, String, String, String, com.android.builder.VariantConfiguration.Type, boolean, com.android.builder.model.AaptOptions)}
@@ -265,24 +265,9 @@
         return mCmdLineRunner;
     }
 
-    /**
-     * Generate the BuildConfig class for the project.
-     * @param packageName the package in which to generate the class
-     * @param debuggable whether the app is considered debuggable
-     * @param javaLines additional java lines to put in the class. These must be valid Java lines.
-     * @param sourceOutputDir directory where to put this. This is the source folder, not the
-     *                        package folder.
-     * @throws IOException
-     */
-    public void generateBuildConfig(
-            @NonNull String packageName,
-                     boolean debuggable,
-            @NonNull List<String> javaLines,
-            @NonNull String sourceOutputDir) throws IOException {
-
-        BuildConfigGenerator generator = new BuildConfigGenerator(
-                sourceOutputDir, packageName, debuggable);
-        generator.generate(javaLines);
+    @NonNull
+    public static ClassField createClassField(@NonNull String type, @NonNull String name, @NonNull String value) {
+        return new ClassFieldImpl(type, name, value);
     }
 
     /**
diff --git a/builder/src/main/java/com/android/builder/DefaultManifestParser.java b/builder/src/main/java/com/android/builder/DefaultManifestParser.java
index 97d8533..e8d70d6 100644
--- a/builder/src/main/java/com/android/builder/DefaultManifestParser.java
+++ b/builder/src/main/java/com/android/builder/DefaultManifestParser.java
@@ -67,6 +67,27 @@
     }
 
     @Override
+    public int getVersionCode(@NonNull File manifestFile) {
+        XPath xpath = AndroidXPathFactory.newXPath();
+
+        try {
+            String value= xpath.evaluate("/manifest/@android:versionCode",
+                    new InputSource(new FileInputStream(manifestFile)));
+            if (value != null) {
+                return Integer.parseInt(value);
+            }
+        } catch (XPathExpressionException e) {
+            // won't happen.
+        } catch (FileNotFoundException e) {
+            throw new RuntimeException(e);
+        } catch (NumberFormatException e) {
+            // return -1 below.
+        }
+
+        return -1;
+    }
+
+    @Override
     public int getMinSdkVersion(@NonNull File manifestFile) {
         try {
             Object value = AndroidManifest.getMinSdkVersion(new FileWrapper(manifestFile));
diff --git a/builder/src/main/java/com/android/builder/ManifestParser.java b/builder/src/main/java/com/android/builder/ManifestParser.java
index 5b6411c..3b8e4a3 100644
--- a/builder/src/main/java/com/android/builder/ManifestParser.java
+++ b/builder/src/main/java/com/android/builder/ManifestParser.java
@@ -21,14 +21,56 @@
 
 import java.io.File;
 
+/**
+ * A Manifest parser
+ */
 public interface ManifestParser {
 
+    /**
+     * Returns the package name parsed from the given manifest file.
+     *
+     * @param manifestFile the manifest file to parse
+     *
+     * @return the package name or null if not found.
+     */
     @Nullable
     String getPackage(@NonNull File manifestFile);
 
+    /**
+     * Returns the minSdkVersion parsed from the given manifest file.
+     *
+     * @param manifestFile the manifest file to parse
+     *
+     * @return the minSdkVersion or 1 if not found.
+     */
     int getMinSdkVersion(@NonNull File manifestFile);
+
+    /**
+     * Returns the targetSdkVersion parsed from the given manifest file.
+     *
+     * @param manifestFile the manifest file to parse
+     *
+     * @return the targetSdkVersion or -1 if not found.
+     */
     int getTargetSdkVersion(@NonNull File manifestFile);
 
+    /**
+     * Returns the version name parsed from the given manifest file.
+     *
+     * @param manifestFile the manifest file to parse
+     *
+     * @return the version name or null if not found.
+     */
     @Nullable
     String getVersionName(@NonNull File manifestFile);
+
+    /**
+     * Returns the version code parsed from the given manifest file.
+     *
+     * @param manifestFile the manifest file to parse
+     *
+     * @return the version code or -1 if not found.
+     */
+    int getVersionCode(@NonNull File manifestFile);
+
 }
diff --git a/builder/src/main/java/com/android/builder/VariantConfiguration.java b/builder/src/main/java/com/android/builder/VariantConfiguration.java
index d21a795..7c5f6b1 100644
--- a/builder/src/main/java/com/android/builder/VariantConfiguration.java
+++ b/builder/src/main/java/com/android/builder/VariantConfiguration.java
@@ -24,6 +24,7 @@
 import com.android.builder.dependency.LibraryDependency;
 import com.android.builder.internal.NdkConfigImpl;
 import com.android.builder.internal.StringHelper;
+import com.android.builder.model.ClassField;
 import com.android.builder.model.ProductFlavor;
 import com.android.builder.model.SigningConfig;
 import com.android.builder.model.SourceProvider;
@@ -35,6 +36,7 @@
 
 import java.io.File;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 
@@ -323,6 +325,26 @@
     }
 
     /**
+     * Return the names of the applied flavors.
+     *
+     * @return the list, possibly empty if there are no flavors.
+     */
+    @NonNull
+    public List<String> getFlavorNames() {
+        if (mFlavorConfigs.isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        List<String> names = Lists.newArrayListWithCapacity(mFlavorConfigs.size());
+        for (DefaultProductFlavor flavor : mFlavorConfigs) {
+            names.add(flavor.getName());
+        }
+
+        return names;
+    }
+
+
+    /**
      * Add a new configured ProductFlavor.
      *
      * If multiple flavors are added, the priority follows the order they are added when it
@@ -640,7 +662,11 @@
 
         if (versionSuffix != null && versionSuffix.length() > 0) {
             if (versionName == null) {
-                versionName = getVersionNameFromManifest();
+                if (mType != Type.TEST) {
+                    versionName = getVersionNameFromManifest();
+                } else {
+                    versionName = "";
+                }
             }
 
             versionName = versionName + versionSuffix;
@@ -649,6 +675,24 @@
         return versionName;
     }
 
+    /**
+     * Returns the version code for this variant. This could be coming from the manifest or
+     * could be overridden through the product flavors, and can have a suffix specified by
+     * the build type.
+     *
+     * @return the version code or -1 if there was non defined.
+     */
+    public int getVersionCode() {
+        int versionCode = mMergedFlavor.getVersionCode();
+
+        if (versionCode == -1 && mType != Type.TEST) {
+
+            versionCode = getVersionCodeFromManifest();
+        }
+
+        return versionCode;
+    }
+
     private final static String DEFAULT_TEST_RUNNER = "android.test.InstrumentationTestRunner";
     private final static Boolean DEFAULT_HANDLE_PROFILING = false;
     private final static Boolean DEFAULT_FUNCTIONAL_TEST = false;
@@ -721,6 +765,14 @@
     }
 
     /**
+     * Reads the version code from the manifest.
+     */
+    public int getVersionCodeFromManifest() {
+        File manifestLocation = mDefaultSourceProvider.getManifestFile();
+        return sManifestParser.getVersionCode(manifestLocation);
+    }
+
+    /**
      * Return the minSdkVersion for this variant.
      *
      * This uses both the value from the manifest (if present), and the override coming
@@ -1115,27 +1167,52 @@
         return Lists.newArrayList(jars);
     }
 
+    /**
+     * Returns a list of items for the BuildConfig class.
+     *
+     * Items can be either fields (instance of {@link com.android.builder.model.ClassField})
+     * or comments (instance of String).
+     *
+     * @return a list of items.
+     */
     @NonNull
-    public List<String> getBuildConfigLines() {
-        List<String> fullList = Lists.newArrayList();
+    public List<Object> getBuildConfigItems() {
+        List<Object> fullList = Lists.newArrayList();
 
-        List<String> list = mDefaultConfig.getBuildConfig();
-        if (!list.isEmpty()) {
-            fullList.add("// lines from default config.");
-            fullList.addAll(list);
-        }
+        Set<String> usedFieldNames = Sets.newHashSet();
 
-        list = mBuildType.getBuildConfig();
+        List<ClassField> list = mBuildType.getBuildConfigFields();
         if (!list.isEmpty()) {
-            fullList.add("// lines from build type: " + mBuildType.getName());
-            fullList.addAll(list);
+            fullList.add("Fields from build type: " + mBuildType.getName());
+            for (ClassField f : list) {
+                usedFieldNames.add(f.getName());
+                fullList.add(f);
+            }
         }
 
         for (DefaultProductFlavor flavor : mFlavorConfigs) {
-            list = flavor.getBuildConfig();
+            list = flavor.getBuildConfigFields();
             if (!list.isEmpty()) {
-                fullList.add("// lines from product flavor: " + flavor.getName());
-                fullList.addAll(list);
+                fullList.add("Fields from product flavor: " + flavor.getName());
+                for (ClassField f : list) {
+                    String name = f.getName();
+                    if (!usedFieldNames.contains(name)) {
+                        usedFieldNames.add(f.getName());
+                        fullList.add(f);
+                    }
+                }
+            }
+        }
+
+        list = mDefaultConfig.getBuildConfigFields();
+        if (!list.isEmpty()) {
+            fullList.add("Fields from default config.");
+            for (ClassField f : list) {
+                String name = f.getName();
+                if (!usedFieldNames.contains(name)) {
+                    usedFieldNames.add(f.getName());
+                    fullList.add(f);
+                }
             }
         }
 
diff --git a/builder/src/main/java/com/android/builder/compiling/BuildConfigGenerator.java b/builder/src/main/java/com/android/builder/compiling/BuildConfigGenerator.java
new file mode 100644
index 0000000..1e298b4
--- /dev/null
+++ b/builder/src/main/java/com/android/builder/compiling/BuildConfigGenerator.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2011 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.compiling;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.builder.AndroidBuilder;
+import com.android.builder.model.ClassField;
+import com.google.common.collect.Lists;
+import com.squareup.javawriter.JavaWriter;
+
+import javax.lang.model.element.Modifier;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Class able to generate a BuildConfig class in Android project.
+ * The BuildConfig class contains constants related to the build target.
+ */
+public class BuildConfigGenerator {
+
+    public final static String BUILD_CONFIG_NAME = "BuildConfig.java";
+
+    private final String mGenFolder;
+    private final String mBuildConfigPackageName;
+
+    private final List<ClassField> mFields = Lists.newArrayList();
+    private List<Object> mItems = Lists.newArrayList();
+
+    /**
+     * Creates a generator
+     * @param genFolder the gen folder of the project
+     * @param buildConfigPackageName the package in which to create the class.
+     */
+    public BuildConfigGenerator(@NonNull String genFolder, @NonNull String buildConfigPackageName) {
+        mGenFolder = checkNotNull(genFolder);
+        mBuildConfigPackageName = checkNotNull(buildConfigPackageName);
+    }
+
+    public BuildConfigGenerator addField(
+            @NonNull String type, @NonNull String name, @NonNull String value) {
+        mFields.add(AndroidBuilder.createClassField(type, name, value));
+        return this;
+    }
+
+    public BuildConfigGenerator addItems(@Nullable Collection<Object> items) {
+        if (items != null) {
+            mItems.addAll(items);
+        }
+        return this;
+    }
+
+    /**
+     * Returns a File representing where the BuildConfig class will be.
+     */
+    public File getFolderPath() {
+        File genFolder = new File(mGenFolder);
+        return new File(genFolder, mBuildConfigPackageName.replace('.', File.separatorChar));
+    }
+
+    public File getBuildConfigFile() {
+        File folder = getFolderPath();
+        return new File(folder, BUILD_CONFIG_NAME);
+    }
+
+    /**
+     * Generates the BuildConfig class.
+     */
+    public void generate() throws IOException {
+        File pkgFolder = getFolderPath();
+        if (!pkgFolder.isDirectory()) {
+            if (!pkgFolder.mkdirs()) {
+                throw new RuntimeException("Failed to create " + pkgFolder.getAbsolutePath());
+            }
+        }
+
+        File buildConfigJava = new File(pkgFolder, BUILD_CONFIG_NAME);
+        FileWriter out = new FileWriter(buildConfigJava);
+
+        JavaWriter writer = new JavaWriter(out);
+
+        Set<Modifier> publicFinal = EnumSet.of(Modifier.PUBLIC, Modifier.FINAL);
+        Set<Modifier> publicFinalStatic = EnumSet.of(Modifier.PUBLIC, Modifier.FINAL, Modifier.STATIC);
+
+        writer.emitJavadoc("Automatically generated file. DO NOT MODIFY")
+                .emitPackage(mBuildConfigPackageName)
+                .beginType("BuildConfig", "class", publicFinal);
+
+        for (ClassField field : mFields) {
+            writer.emitField(
+                    field.getType(),
+                    field.getName(),
+                    publicFinalStatic,
+                    field.getValue());
+        }
+
+        for (Object item : mItems) {
+            if (item instanceof ClassField) {
+                ClassField field = (ClassField)item;
+                writer.emitField(
+                        field.getType(),
+                        field.getName(),
+                        publicFinalStatic,
+                        field.getValue());
+
+            } else if (item instanceof String) {
+                writer.emitSingleLineComment((String) item);
+            }
+        }
+
+        writer.endType();
+
+        out.close();
+    }
+}
diff --git a/builder/src/main/java/com/android/builder/internal/BaseConfigImpl.java b/builder/src/main/java/com/android/builder/internal/BaseConfigImpl.java
index 044420b..62653d3 100644
--- a/builder/src/main/java/com/android/builder/internal/BaseConfigImpl.java
+++ b/builder/src/main/java/com/android/builder/internal/BaseConfigImpl.java
@@ -18,11 +18,13 @@
 
 import com.android.annotations.NonNull;
 import com.android.builder.model.BaseConfig;
+import com.android.builder.model.ClassField;
 import com.google.common.collect.Lists;
 
 import java.io.File;
 import java.io.Serializable;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
 
 /**
@@ -31,24 +33,28 @@
 public class BaseConfigImpl implements Serializable, BaseConfig {
     private static final long serialVersionUID = 1L;
 
-    private final List<String> mBuildConfigLines = Lists.newArrayList();
+    private final List<ClassField> mBuildConfigFields = Lists.newArrayList();
     private final List<File> mProguardFiles = Lists.newArrayList();
     private final List<File> mConsumerProguardFiles = Lists.newArrayList();
 
-    public void setBuildConfig(String... lines) {
-        mBuildConfigLines.clear();
-        mBuildConfigLines.addAll(Arrays.asList(lines));
+    public void setBuildConfigFields(@NonNull ClassField... fields) {
+        mBuildConfigFields.clear();
+        mBuildConfigFields.addAll(Arrays.asList(fields));
     }
 
-    public void setBuildConfig(String line) {
-        mBuildConfigLines.clear();
-        mBuildConfigLines.add(line);
+    public void setBuildConfigFields(@NonNull Collection<ClassField> fields) {
+        mBuildConfigFields.clear();
+        mBuildConfigFields.addAll(fields);
+    }
+
+    public void addBuildConfigField(@NonNull ClassField field) {
+        mBuildConfigFields.add(field);
     }
 
     @Override
     @NonNull
-    public List<String> getBuildConfig() {
-        return mBuildConfigLines;
+    public List<ClassField> getBuildConfigFields() {
+        return mBuildConfigFields;
     }
 
     @Override
@@ -64,8 +70,7 @@
     }
 
     protected void _initWith(BaseConfig that) {
-        mBuildConfigLines.clear();
-        mBuildConfigLines.addAll(that.getBuildConfig());
+        setBuildConfigFields(that.getBuildConfigFields());
 
         mProguardFiles.clear();
         mProguardFiles.addAll(that.getProguardFiles());
@@ -81,7 +86,7 @@
 
         BaseConfigImpl that = (BaseConfigImpl) o;
 
-        if (!mBuildConfigLines.equals(that.mBuildConfigLines)) return false;
+        if (!mBuildConfigFields.equals(that.mBuildConfigFields)) return false;
         if (!mProguardFiles.equals(that.mProguardFiles)) return false;
         if (!mConsumerProguardFiles.equals(that.mConsumerProguardFiles)) return false;
 
@@ -90,7 +95,7 @@
 
     @Override
     public int hashCode() {
-        int result = mBuildConfigLines.hashCode();
+        int result = mBuildConfigFields.hashCode();
         result = 31 * result + mProguardFiles.hashCode();
         result = 31 * result + mConsumerProguardFiles.hashCode();
         return result;
diff --git a/builder/src/main/java/com/android/builder/internal/BuildConfigGenerator.java b/builder/src/main/java/com/android/builder/internal/BuildConfigGenerator.java
deleted file mode 100644
index 2d01734..0000000
--- a/builder/src/main/java/com/android/builder/internal/BuildConfigGenerator.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2011 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.internal;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.google.common.collect.Maps;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-import java.util.Map;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-/**
- * Class able to generate a BuildConfig class in Android project.
- * The BuildConfig class contains constants related to the build target.
- */
-public class BuildConfigGenerator {
-
-    private final static String TEMPLATE = "BuildConfig.template";
-    private final static String PH_PACKAGE = "#PACKAGE#";
-    private final static String PH_DEBUG = "#DEBUG#";
-    private final static String PH_LINES = "#ADDITIONAL_LINES#";
-
-    private final String mGenFolder;
-    private final String mAppPackage;
-    private final boolean mDebug;
-
-    public final static String BUILD_CONFIG_NAME = "BuildConfig.java";
-
-    /**
-     * Creates a generator
-     * @param genFolder the gen folder of the project
-     * @param appPackage the application package
-     * @param debug whether it's a debug build
-     */
-    public BuildConfigGenerator(@NonNull String genFolder, @NonNull String appPackage,
-                                boolean debug) {
-        mGenFolder = checkNotNull(genFolder);
-        mAppPackage = checkNotNull(appPackage);
-        mDebug = debug;
-    }
-
-    /**
-     * Returns a File representing where the BuildConfig class will be.
-     */
-    public File getFolderPath() {
-        File genFolder = new File(mGenFolder);
-        return new File(genFolder, mAppPackage.replace('.', File.separatorChar));
-    }
-
-    public File getBuildConfigFile() {
-        File folder = getFolderPath();
-        return new File(folder, BUILD_CONFIG_NAME);
-    }
-
-    /**
-     * Generates the BuildConfig class.
-     * @param additionalLines a list of additional lines to be added to the class.
-     */
-    public void generate(@Nullable List<String> additionalLines) throws IOException {
-        Map<String, String> map = Maps.newHashMap();
-        map.put(PH_PACKAGE, mAppPackage);
-
-        // Hack (see IDEA-100046): We want to avoid reporting "condition is always true"
-        // from the data flow inspection, so use a non-constant value. However, that defeats
-        // the purpose of this flag (when not in debug mode, if (BuildConfig.DEBUG && ...) will
-        // be completely removed by the compiler), so as a hack we do it only for the case
-        // where debug is true, which is the most likely scenario while the user is looking
-        // at source code.
-        //map.put(PH_DEBUG, Boolean.toString(mDebug));
-        map.put(PH_DEBUG, mDebug ? "Boolean.parseBoolean(\"true\")" : "false");
-
-        if (additionalLines != null) {
-            StringBuilder sb = new StringBuilder();
-            for (String line : additionalLines) {
-                sb.append("    ").append(line).append('\n');
-            }
-            map.put(PH_LINES, sb.toString());
-
-        } else {
-            map.put(PH_LINES, "");
-        }
-
-        File pkgFolder = getFolderPath();
-        if (!pkgFolder.isDirectory()) {
-            pkgFolder.mkdirs();
-        }
-
-        File buildConfigJava = new File(pkgFolder, BUILD_CONFIG_NAME);
-
-        TemplateProcessor processor = new TemplateProcessor(
-                BuildConfigGenerator.class.getResourceAsStream(TEMPLATE), map);
-        processor.generate(buildConfigJava);
-    }
-}
diff --git a/builder/src/main/java/com/android/builder/internal/ClassFieldImpl.java b/builder/src/main/java/com/android/builder/internal/ClassFieldImpl.java
new file mode 100644
index 0000000..44824b4
--- /dev/null
+++ b/builder/src/main/java/com/android/builder/internal/ClassFieldImpl.java
@@ -0,0 +1,86 @@
+/*
+ * 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.internal;
+
+import com.android.annotations.NonNull;
+import com.android.builder.model.ClassField;
+
+import java.io.Serializable;
+
+/**
+ */
+public final class ClassFieldImpl implements ClassField, Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @NonNull
+    private final String type;
+    @NonNull
+    private final String name;
+    @NonNull
+    private final String value;
+
+    public ClassFieldImpl(@NonNull String type, @NonNull String name, @NonNull String value) {
+        //noinspection ConstantConditions
+        if (type == null || name == null || value == null) {
+            throw new NullPointerException("Build Config field cannot have a null parameter");
+        }
+        this.type = type;
+        this.name = name;
+        this.value = value;
+    }
+
+    @Override
+    @NonNull
+    public String getType() {
+        return type;
+    }
+
+    @Override
+    @NonNull
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    @NonNull
+    public String getValue() {
+        return value;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        ClassFieldImpl that = (ClassFieldImpl) o;
+
+        if (!name.equals(that.name)) return false;
+        if (!type.equals(that.type)) return false;
+        if (!value.equals(that.value)) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = type.hashCode();
+        result = 31 * result + name.hashCode();
+        result = 31 * result + value.hashCode();
+        return result;
+    }
+}
diff --git a/builder/src/main/resources/com/android/builder/internal/BuildConfig.template b/builder/src/main/resources/com/android/builder/internal/BuildConfig.template
deleted file mode 100644
index 71b4b9c..0000000
--- a/builder/src/main/resources/com/android/builder/internal/BuildConfig.template
+++ /dev/null
@@ -1,7 +0,0 @@
-/** Automatically generated file. DO NOT MODIFY */
-package #PACKAGE#;
-
-public final class BuildConfig {
-    public static final boolean DEBUG = #DEBUG#;
-
-#ADDITIONAL_LINES#}
\ No newline at end of file
diff --git a/builder/src/test/java/com/android/builder/VariantConfigurationTest.java b/builder/src/test/java/com/android/builder/VariantConfigurationTest.java
index 424a5f3..dfe8ea4 100644
--- a/builder/src/test/java/com/android/builder/VariantConfigurationTest.java
+++ b/builder/src/test/java/com/android/builder/VariantConfigurationTest.java
@@ -57,6 +57,11 @@
         public String getVersionName(@NonNull File manifestFile) {
             return "1.0";
         }
+
+        @Override
+        public int getVersionCode(@NonNull File manifestFile) {
+            return 1;
+        }
     }
 
     @Override
diff --git a/builder/src/test/java/com/android/builder/compiling/BuildConfigGeneratorTest.java b/builder/src/test/java/com/android/builder/compiling/BuildConfigGeneratorTest.java
new file mode 100644
index 0000000..0bb2200
--- /dev/null
+++ b/builder/src/test/java/com/android/builder/compiling/BuildConfigGeneratorTest.java
@@ -0,0 +1,102 @@
+/*
+ * 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.compiling;
+
+import com.android.builder.AndroidBuilder;
+import com.google.common.base.Charsets;
+import com.google.common.collect.Lists;
+import com.google.common.io.Files;
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.util.List;
+
+@SuppressWarnings("ResultOfMethodCallIgnored")
+public class BuildConfigGeneratorTest extends TestCase {
+    public void testFalse() throws Exception {
+        File tempDir = Files.createTempDir();
+        BuildConfigGenerator generator = new BuildConfigGenerator(tempDir.getPath(),
+                "my.app.pkg");
+
+        generator.addField("boolean", "DEBUG", "false").generate();
+
+        File file = generator.getBuildConfigFile();
+        assertTrue(file.exists());
+        String actual = Files.toString(file, Charsets.UTF_8);
+        assertEquals(
+                "/**\n" +
+                " * Automatically generated file. DO NOT MODIFY\n" +
+                " */\n" +
+                "package my.app.pkg;\n" +
+                "\n" +
+                "public final class BuildConfig {\n" +
+                "  public static final boolean DEBUG = false;\n" +
+                "}\n", actual);
+        file.delete();
+        tempDir.delete();
+    }
+
+    public void testTrue() throws Exception {
+        File tempDir = Files.createTempDir();
+        BuildConfigGenerator generator = new BuildConfigGenerator(tempDir.getPath(),
+                "my.app.pkg");
+        generator.addField("boolean", "DEBUG", "Boolean.parseBoolean(\"true\")").generate();
+
+        File file = generator.getBuildConfigFile();
+        assertTrue(file.exists());
+        String actual = Files.toString(file, Charsets.UTF_8);
+        assertEquals(
+                "/**\n" +
+                " * Automatically generated file. DO NOT MODIFY\n" +
+                " */\n" +
+                "package my.app.pkg;\n" +
+                "\n" +
+                "public final class BuildConfig {\n" +
+                "  public static final boolean DEBUG = Boolean.parseBoolean(\"true\");\n" +
+                "}\n", actual);
+        file.delete();
+        tempDir.delete();
+    }
+
+    public void testExtra() throws Exception {
+        File tempDir = Files.createTempDir();
+        BuildConfigGenerator generator = new BuildConfigGenerator(tempDir.getPath(),
+                "my.app.pkg");
+
+        List<Object> items = Lists.newArrayList();
+        items.add("Extra line");
+        items.add(AndroidBuilder.createClassField("int", "EXTRA", "42"));
+
+        generator.addItems(items).generate();
+
+        File file = generator.getBuildConfigFile();
+        assertTrue(file.exists());
+        String actual = Files.toString(file, Charsets.UTF_8);
+        assertEquals(
+                "/**\n" +
+                " * Automatically generated file. DO NOT MODIFY\n" +
+                " */\n" +
+                "package my.app.pkg;\n" +
+                "\n" +
+                "public final class BuildConfig {\n" +
+                "  // Extra line\n" +
+                "  public static final int EXTRA = 42;\n" +
+                "}\n", actual);
+        file.delete();
+        tempDir.delete();
+    }
+}
diff --git a/builder/src/test/java/com/android/builder/internal/BuildConfigGeneratorTest.java b/builder/src/test/java/com/android/builder/internal/BuildConfigGeneratorTest.java
deleted file mode 100644
index 0f5ecd3..0000000
--- a/builder/src/test/java/com/android/builder/internal/BuildConfigGeneratorTest.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package com.android.builder.internal;
-
-import com.google.common.base.Charsets;
-import com.google.common.io.Files;
-
-import junit.framework.TestCase;
-
-import java.io.File;
-import java.util.Arrays;
-import java.util.Collections;
-
-@SuppressWarnings("ResultOfMethodCallIgnored")
-public class BuildConfigGeneratorTest extends TestCase {
-    public void testFalse() throws Exception {
-        File tempDir = Files.createTempDir();
-        BuildConfigGenerator generator = new BuildConfigGenerator(tempDir.getPath(),
-                "my.app.pkg", false);
-        generator.generate(Collections.<String>emptyList());
-        File file = generator.getBuildConfigFile();
-        assertTrue(file.exists());
-        String actual = Files.toString(file, Charsets.UTF_8);
-        assertEquals(
-                "/** Automatically generated file. DO NOT MODIFY */\n"
-                + "package my.app.pkg;\n"
-                + "\n"
-                + "public final class BuildConfig {\n"
-                + "    public static final boolean DEBUG = false;\n"
-                + "\n"
-                + "}", actual);
-        file.delete();
-        tempDir.delete();
-    }
-
-    public void testTrue() throws Exception {
-        File tempDir = Files.createTempDir();
-        BuildConfigGenerator generator = new BuildConfigGenerator(tempDir.getPath(),
-                "my.app.pkg", true);
-        generator.generate(Collections.<String>emptyList());
-        File file = generator.getBuildConfigFile();
-        assertTrue(file.exists());
-        String actual = Files.toString(file, Charsets.UTF_8);
-        assertEquals(
-                "/** Automatically generated file. DO NOT MODIFY */\n"
-                + "package my.app.pkg;\n"
-                + "\n"
-                + "public final class BuildConfig {\n"
-                + "    public static final boolean DEBUG = Boolean.parseBoolean(\"true\");\n"
-                + "\n"
-                + "}", actual);
-        file.delete();
-        tempDir.delete();
-    }
-
-    public void testExtra() throws Exception {
-        File tempDir = Files.createTempDir();
-        BuildConfigGenerator generator = new BuildConfigGenerator(tempDir.getPath(),
-                "my.app.pkg", false);
-        generator.generate(Arrays.asList("// Extra line:", "public static int EXTRA = 42;"));
-        File file = generator.getBuildConfigFile();
-        assertTrue(file.exists());
-        String actual = Files.toString(file, Charsets.UTF_8);
-        assertEquals(
-                "/** Automatically generated file. DO NOT MODIFY */\n"
-                + "package my.app.pkg;\n"
-                + "\n"
-                + "public final class BuildConfig {\n"
-                + "    public static final boolean DEBUG = false;\n"
-                + "\n"
-                + "    // Extra line:\n"
-                + "    public static int EXTRA = 42;\n"
-                + "}", actual);
-        file.delete();
-        tempDir.delete();
-    }
-}
diff --git a/changelog.txt b/changelog.txt
index 70ed31e..6525120 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -3,10 +3,18 @@
 - You can now have a variant specific source folder if you have flavors.
   Only for app (not library or test). Name is src/flavorDebug/... or src/flavor1Flavor2Debug/
   (note the camelcase naming, with lower case for first letter).
-  Its compoenents (res, manifest, etc...) have higher priority than components from build type
+  Its components (res, manifest, etc...) have higher priority than components from build type
   or flavors.
   It also comes with dependency configuration, so you can do 
      flavorDebugCompile '...'
+- Build config improvements and DSL changes.
+  The previous DSL proprety:
+    buildConfigLine "<value>"
+  has changed to
+    buildConfigField "<type>", "<name>", "<value>"
+  This allows override a field (see 'basic' sample)
+  Also, BuildConfig now automatically contains constants for
+  PACKAGE_NAME, VERSION_CODE, VERSION_NAME, BUILD_TYPE, FLAVOR s well as FLAVOR1, FLAVOR2, etc... if there are several flavor dimensions.
 - Switch to ProGuard 4.10
    - Added ability to test proguarded (obfuscated) apps.
 - Jar files are now pre-dexed for faster dexing.
diff --git a/gradle/src/main/groovy/com/android/build/gradle/BasePlugin.groovy b/gradle/src/main/groovy/com/android/build/gradle/BasePlugin.groovy
index d442514..ab56022 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/BasePlugin.groovy
+++ b/gradle/src/main/groovy/com/android/build/gradle/BasePlugin.groovy
@@ -374,7 +374,7 @@
             getManifestDependencies(config.directLibraries)
         }
         processManifestTask.conventionMapping.versionCode = {
-            mergedFlavor.versionCode
+            config.versionCode
         }
         processManifestTask.conventionMapping.minSdkVersion = {
             mergedFlavor.minSdkVersion
@@ -549,16 +549,40 @@
         generateBuildConfigTask.plugin = this
         generateBuildConfigTask.variant = variantData
 
-        generateBuildConfigTask.conventionMapping.packageName = {
+        generateBuildConfigTask.conventionMapping.buildConfigPackageName = {
             variantConfiguration.originalPackageName
         }
 
+        generateBuildConfigTask.conventionMapping.appPackageName = {
+            variantConfiguration.packageName
+        }
+
+        generateBuildConfigTask.conventionMapping.versionName = {
+            variantConfiguration.versionName
+        }
+
+        generateBuildConfigTask.conventionMapping.versionCode = {
+            variantConfiguration.versionCode
+        }
+
         generateBuildConfigTask.conventionMapping.debuggable = {
             variantConfiguration.buildType.isDebuggable()
         }
 
-        generateBuildConfigTask.conventionMapping.javaLines = {
-            variantConfiguration.buildConfigLines
+        generateBuildConfigTask.conventionMapping.buildTypeName = {
+            variantConfiguration.buildType.name
+        }
+
+        generateBuildConfigTask.conventionMapping.flavorName = {
+            variantConfiguration.flavorName
+        }
+
+        generateBuildConfigTask.conventionMapping.flavorNames = {
+            variantConfiguration.flavorNames
+        }
+
+        generateBuildConfigTask.conventionMapping.items = {
+            variantConfiguration.buildConfigItems
         }
 
         generateBuildConfigTask.conventionMapping.sourceOutputDir = {
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/BuildTypeDsl.groovy b/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/BuildTypeDsl.groovy
index 6ca387c..a4770b6 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/BuildTypeDsl.groovy
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/BuildTypeDsl.groovy
@@ -18,6 +18,7 @@
 import com.android.annotations.NonNull
 import com.android.annotations.Nullable
 import com.android.annotations.VisibleForTesting
+import com.android.builder.AndroidBuilder
 import com.android.builder.BuilderConstants
 import com.android.builder.DefaultBuildType
 import com.android.builder.NdkConfig
@@ -25,7 +26,6 @@
 import org.gradle.api.Action
 import org.gradle.api.internal.file.FileResolver
 import org.gradle.internal.reflect.Instantiator
-
 /**
  * DSL overlay to make methods that accept String... work.
  */
@@ -82,12 +82,11 @@
 
     // -- DSL Methods. TODO remove once the instantiator does what I expect it to do.
 
-    public void buildConfig(String... lines) {
-        setBuildConfig(lines)
-    }
-
-    public void buildConfig(String line) {
-        setBuildConfig(line)
+    public void buildConfigField(
+            @NonNull String type,
+            @NonNull String name,
+            @NonNull String value) {
+        addBuildConfigField(AndroidBuilder.createClassField(type, name, value));
     }
 
     @NonNull
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/ProductFlavorDsl.groovy b/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/ProductFlavorDsl.groovy
index 6b78c86..1645a03 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/ProductFlavorDsl.groovy
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/ProductFlavorDsl.groovy
@@ -17,6 +17,7 @@
 package com.android.build.gradle.internal.dsl
 import com.android.annotations.NonNull
 import com.android.annotations.Nullable
+import com.android.builder.AndroidBuilder
 import com.android.builder.DefaultProductFlavor
 import com.android.builder.NdkConfig
 import org.gradle.api.Action
@@ -50,12 +51,11 @@
 
     // -- DSL Methods. TODO remove once the instantiator does what I expect it to do.
 
-    public void buildConfig(String... lines) {
-        setBuildConfig(lines)
-    }
-
-    public void buildConfig(String line) {
-        setBuildConfig(line)
+    public void buildConfigField(
+            @NonNull String type,
+            @NonNull String name,
+            @NonNull String value) {
+        addBuildConfigField(AndroidBuilder.createClassField(type, name, value));
     }
 
     @NonNull
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/model/BuildTypeImpl.java b/gradle/src/main/groovy/com/android/build/gradle/internal/model/BuildTypeImpl.java
index 03daa6f..ccb1e8b 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/model/BuildTypeImpl.java
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/model/BuildTypeImpl.java
@@ -20,6 +20,7 @@
 import com.android.annotations.Nullable;
 import com.android.builder.NdkConfig;
 import com.android.builder.model.BuildType;
+import com.android.builder.model.ClassField;
 
 import java.io.File;
 import java.io.Serializable;
@@ -112,7 +113,7 @@
 
     @NonNull
     @Override
-    public List<String> getBuildConfig() {
+    public List<ClassField> getBuildConfigFields() {
         return Collections.emptyList();
     }
 
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/model/ProductFlavorImpl.java b/gradle/src/main/groovy/com/android/build/gradle/internal/model/ProductFlavorImpl.java
index d03ae14..8380ae3 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/model/ProductFlavorImpl.java
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/model/ProductFlavorImpl.java
@@ -19,6 +19,7 @@
 import com.android.annotations.NonNull;
 import com.android.annotations.Nullable;
 import com.android.builder.NdkConfig;
+import com.android.builder.model.ClassField;
 import com.android.builder.model.ProductFlavor;
 
 import java.io.File;
@@ -142,7 +143,7 @@
 
     @NonNull
     @Override
-    public List<String> getBuildConfig() {
+    public List<ClassField> getBuildConfigFields() {
         return Collections.emptyList();
     }
 
diff --git a/gradle/src/main/groovy/com/android/build/gradle/tasks/GenerateBuildConfig.groovy b/gradle/src/main/groovy/com/android/build/gradle/tasks/GenerateBuildConfig.groovy
index 35bc489..cba93f0 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/tasks/GenerateBuildConfig.groovy
+++ b/gradle/src/main/groovy/com/android/build/gradle/tasks/GenerateBuildConfig.groovy
@@ -16,7 +16,9 @@
 package com.android.build.gradle.tasks
 
 import com.android.build.gradle.internal.tasks.IncrementalTask
+import com.android.builder.compiling.BuildConfigGenerator
 import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.Optional
 import org.gradle.api.tasks.OutputDirectory
 
 public class GenerateBuildConfig extends IncrementalTask {
@@ -29,13 +31,31 @@
     // ----- PRIVATE TASK API -----
 
     @Input
-    String packageName
+    String buildConfigPackageName
+
+    @Input
+    String appPackageName
 
     @Input
     boolean debuggable
 
     @Input
-    List<String> javaLines;
+    String flavorName
+
+    @Input
+    List<String> flavorNames
+
+    @Input
+    String buildTypeName
+
+    @Input @Optional
+    String versionName
+
+    @Input
+    int versionCode
+
+    @Input
+    List<Object> items;
 
     @Override
     protected void doFullTaskAction() {
@@ -44,10 +64,33 @@
         File destinationDir = getSourceOutputDir()
         emptyFolder(destinationDir)
 
-        getBuilder().generateBuildConfig(
-                getPackageName(),
-                isDebuggable(),
-                getJavaLines(),
-                getSourceOutputDir().absolutePath);
+        BuildConfigGenerator generator = new BuildConfigGenerator(
+                getSourceOutputDir().absolutePath,
+                getBuildConfigPackageName());
+
+        // Hack (see IDEA-100046): We want to avoid reporting "condition is always true"
+        // from the data flow inspection, so use a non-constant value. However, that defeats
+        // the purpose of this flag (when not in debug mode, if (BuildConfig.DEBUG && ...) will
+        // be completely removed by the compiler), so as a hack we do it only for the case
+        // where debug is true, which is the most likely scenario while the user is looking
+        // at source code.
+        //map.put(PH_DEBUG, Boolean.toString(mDebug));
+        generator.addField("boolean", "DEBUG", getDebuggable() ? "Boolean.parseBoolean(\"true\")" : "false")
+            .addField("String", "PACKAGE_NAME", "\"${getAppPackageName()}\"")
+            .addField("String", "BUILD_TYPE", "\"${getBuildTypeName()}\"")
+            .addField("String", "FLAVOR", "\"${getFlavorName()}\"")
+            .addField("int", "VERSION_CODE", Integer.toString(getVersionCode()))
+            .addItems(getItems());
+
+        if (getVersionName() != null) {
+            generator.addField("String", "VERSION_NAME", "\"${getVersionName()}\"")
+        }
+
+        int i = 1;
+        for (String name : getFlavorNames()) {
+            generator.addField("String", "FLAVOR${i++}", "\"$name\"")
+        }
+
+        generator.generate();
     }
 }
diff --git a/tests/basic/build.gradle b/tests/basic/build.gradle
index b020f58..b713714 100644
--- a/tests/basic/build.gradle
+++ b/tests/basic/build.gradle
@@ -43,8 +43,8 @@
         testInstrumentationRunner "android.test.InstrumentationTestRunner"
         testHandleProfiling false
 
-        buildConfig "private final static boolean DEFAULT = true;", \
-                    "private final static String FOO = \"foo\";"
+        buildConfigField "boolean", "DEFAULT", "true"
+        buildConfigField "String", "FOO", "\"foo\""
     }
 
     buildTypes {
@@ -52,7 +52,7 @@
             packageNameSuffix ".debug"
             signingConfig signingConfigs.myConfig
 
-            buildConfig "private final static boolean DEBUG2 = false;"
+            buildConfigField "String", "FOO", "\"bar\""
         }
     }
 
diff --git a/tests/basic/src/instrumentTest/java/com/android/tests/basic/MainTest.java b/tests/basic/src/instrumentTest/java/com/android/tests/basic/MainTest.java
index 7cf7329..9f4b2de 100644
--- a/tests/basic/src/instrumentTest/java/com/android/tests/basic/MainTest.java
+++ b/tests/basic/src/instrumentTest/java/com/android/tests/basic/MainTest.java
@@ -34,5 +34,10 @@
     public void testPreconditions() {
         assertNotNull(mTextView);
     }
+
+    @MediumTest
+    public void testBuildConfig() {
+        assertEquals("bar", BuildConfig.FOO);
+    }
 }
 
diff --git a/tests/flavored/build.gradle b/tests/flavored/build.gradle
index 41e50d9..d08c3fe 100644
--- a/tests/flavored/build.gradle
+++ b/tests/flavored/build.gradle
@@ -15,28 +15,23 @@
     testBuildType = "staging"
 
     defaultConfig {
-        buildConfig "private final static boolean DEFAULT = true;", \
-                    "private final static String FOO = \"foo\";"
     }
 
     productFlavors {
         f1 {
             packageName = "com.android.tests.flavored.f1"
             versionName = "1.0.0-f1"
-            buildConfig "public final static String FLAVOR = \"f1\";"
         }
         f2 {
             packageName = "com.android.tests.flavored.f2"
             versionName = "1.0.0-f2"
-            buildConfig "public final static String FLAVOR = \"f2\";"
         }
     }
-    
+
     buildTypes {
         debug {
             packageNameSuffix = ".debug"
             versionNameSuffix = ".D"
-            buildConfig "private final static boolean DEBUG2 = false;"
         }
         staging {
             packageNameSuffix = ".staging"
diff --git a/tests/flavors/build.gradle b/tests/flavors/build.gradle
index d3f5940..1b1c683 100644
--- a/tests/flavors/build.gradle
+++ b/tests/flavors/build.gradle
@@ -17,21 +17,16 @@
     productFlavors {
         f1 {
             flavorGroup   "group1"
-
-            buildConfig   "public final static String GROUP1 = \"F1\";"
         }
         f2 {
             flavorGroup   "group1"
-            buildConfig   "public final static String GROUP1 = \"F2\";"
         }
 
         fa {
             flavorGroup   "group2"
-            buildConfig   "public final static String GROUP2 = \"FA\";"
         }
         fb {
             flavorGroup   "group2"
-            buildConfig   "public final static String GROUP2 = \"FB\";"
         }
     }
 }
diff --git a/tests/flavors/src/f1/java/com/android/tests/flavors/group1/SomeClass.java b/tests/flavors/src/f1/java/com/android/tests/flavors/group1/SomeClass.java
index a5c30b2..ffbf5ab 100644
--- a/tests/flavors/src/f1/java/com/android/tests/flavors/group1/SomeClass.java
+++ b/tests/flavors/src/f1/java/com/android/tests/flavors/group1/SomeClass.java
@@ -2,6 +2,6 @@
 
 public class SomeClass {
     public static String getString() {
-        return "F1";
+        return "f1";
     }
 }
\ No newline at end of file
diff --git a/tests/flavors/src/f1/res/values/strings.xml b/tests/flavors/src/f1/res/values/strings.xml
index 73e7584..b4db3e8 100644
--- a/tests/flavors/src/f1/res/values/strings.xml
+++ b/tests/flavors/src/f1/res/values/strings.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
 
-    <string name="group1_string">F1</string>
-    <string name="general_string">F1</string>
+    <string name="group1_string">f1</string>
+    <string name="general_string">f1</string>
 
 </resources>
\ No newline at end of file
diff --git a/tests/flavors/src/f2/java/com/android/tests/flavors/group1/SomeClass.java b/tests/flavors/src/f2/java/com/android/tests/flavors/group1/SomeClass.java
index 5974587..09327a6 100644
--- a/tests/flavors/src/f2/java/com/android/tests/flavors/group1/SomeClass.java
+++ b/tests/flavors/src/f2/java/com/android/tests/flavors/group1/SomeClass.java
@@ -2,6 +2,6 @@
 
 public class SomeClass {
     public static String getString() {
-        return "F2";
+        return "f2";
     }
 }
\ No newline at end of file
diff --git a/tests/flavors/src/f2/res/values/strings.xml b/tests/flavors/src/f2/res/values/strings.xml
index 855e7f6..7a306fc 100644
--- a/tests/flavors/src/f2/res/values/strings.xml
+++ b/tests/flavors/src/f2/res/values/strings.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
 
-    <string name="group1_string">F2</string>
-    <string name="general_string">F2</string>
+    <string name="group1_string">f2</string>
+    <string name="general_string">f2</string>
 
 </resources>
\ No newline at end of file
diff --git a/tests/flavors/src/fa/java/com/android/tests/flavors/group2/SomeClass.java b/tests/flavors/src/fa/java/com/android/tests/flavors/group2/SomeClass.java
index 40a939e..ae7677b 100644
--- a/tests/flavors/src/fa/java/com/android/tests/flavors/group2/SomeClass.java
+++ b/tests/flavors/src/fa/java/com/android/tests/flavors/group2/SomeClass.java
@@ -2,6 +2,6 @@
 
 public class SomeClass {
     public static String getString() {
-        return "FA";
+        return "fa";
     }
 }
\ No newline at end of file
diff --git a/tests/flavors/src/fa/res/values/strings.xml b/tests/flavors/src/fa/res/values/strings.xml
index 331cb90..f8cefe7 100644
--- a/tests/flavors/src/fa/res/values/strings.xml
+++ b/tests/flavors/src/fa/res/values/strings.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
 
-    <string name="group2_string">FA</string>
-    <string name="general_string">FA</string>
+    <string name="group2_string">fa</string>
+    <string name="general_string">fa</string>
 
 </resources>
\ No newline at end of file
diff --git a/tests/flavors/src/fb/java/com/android/tests/flavors/group2/SomeClass.java b/tests/flavors/src/fb/java/com/android/tests/flavors/group2/SomeClass.java
index 7441b61..5768d64 100644
--- a/tests/flavors/src/fb/java/com/android/tests/flavors/group2/SomeClass.java
+++ b/tests/flavors/src/fb/java/com/android/tests/flavors/group2/SomeClass.java
@@ -2,6 +2,6 @@
 
 public class SomeClass {
     public static String getString() {
-        return "FB";
+        return "fb";
     }
 }
\ No newline at end of file
diff --git a/tests/flavors/src/fb/res/values/strings.xml b/tests/flavors/src/fb/res/values/strings.xml
index fa0733f..8fa24dc 100644
--- a/tests/flavors/src/fb/res/values/strings.xml
+++ b/tests/flavors/src/fb/res/values/strings.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
 
-    <string name="group2_string">FB</string>
-    <string name="general_string">FB</string>
+    <string name="group2_string">fb</string>
+    <string name="general_string">fb</string>
 
 </resources>
\ No newline at end of file
diff --git a/tests/flavors/src/instrumentTestF1/java/com/android/tests/flavors/MainActivityGroup1Test.java b/tests/flavors/src/instrumentTestF1/java/com/android/tests/flavors/MainActivityGroup1Test.java
index 2c043ef..9379d96 100644
--- a/tests/flavors/src/instrumentTestF1/java/com/android/tests/flavors/MainActivityGroup1Test.java
+++ b/tests/flavors/src/instrumentTestF1/java/com/android/tests/flavors/MainActivityGroup1Test.java
@@ -80,17 +80,17 @@
 
     @MediumTest
     public void testResOverlay() {
-        assertEquals("F1", mResOverLay.getText());
-        assertEquals("F1", mResOverLay1.getText());
+        assertEquals("f1", mResOverLay.getText());
+        assertEquals("f1", mResOverLay1.getText());
     }
 
     @MediumTest
     public void testBuildConfig() {
-        assertEquals("F1", mBuildConfig1.getText());
+        assertEquals("f1", mBuildConfig1.getText());
     }
 
     @MediumTest
     public void testCodeOverlay() {
-        assertEquals("F1", mCodeOverlay1.getText());
+        assertEquals("f1", mCodeOverlay1.getText());
     }
 }
diff --git a/tests/flavors/src/instrumentTestF2/java/com/android/tests/flavors/MainActivityGroup1Test.java b/tests/flavors/src/instrumentTestF2/java/com/android/tests/flavors/MainActivityGroup1Test.java
index 41e9ecf..8ecd057 100644
--- a/tests/flavors/src/instrumentTestF2/java/com/android/tests/flavors/MainActivityGroup1Test.java
+++ b/tests/flavors/src/instrumentTestF2/java/com/android/tests/flavors/MainActivityGroup1Test.java
@@ -80,17 +80,17 @@
 
     @MediumTest
     public void testResOverlay() {
-        assertEquals("F2", mResOverLay.getText());
-        assertEquals("F2", mResOverLay1.getText());
+        assertEquals("f2", mResOverLay.getText());
+        assertEquals("f2", mResOverLay1.getText());
     }
 
     @MediumTest
     public void testBuildConfig() {
-        assertEquals("F2", mBuildConfig1.getText());
+        assertEquals("f2", mBuildConfig1.getText());
     }
 
     @MediumTest
     public void testCodeOverlay() {
-        assertEquals("F2", mCodeOverlay1.getText());
+        assertEquals("f2", mCodeOverlay1.getText());
     }
 }
diff --git a/tests/flavors/src/instrumentTestFa/java/com/android/tests/flavors/MainActivityGroup2Test.java b/tests/flavors/src/instrumentTestFa/java/com/android/tests/flavors/MainActivityGroup2Test.java
index 0d0fee2..3e51225 100644
--- a/tests/flavors/src/instrumentTestFa/java/com/android/tests/flavors/MainActivityGroup2Test.java
+++ b/tests/flavors/src/instrumentTestFa/java/com/android/tests/flavors/MainActivityGroup2Test.java
@@ -82,17 +82,17 @@
     public void testResOverlay() {
         // because this group has lower priority, we check that the resource from
         // this flavor is not used.
-        assertFalse("FA".equals(mResOverLay.getText()));
-        assertEquals("FA", mResOverLay2.getText());
+        assertFalse("fa".equals(mResOverLay.getText()));
+        assertEquals("fa", mResOverLay2.getText());
     }
 
     @MediumTest
     public void testBuildConfig() {
-        assertEquals("FA", mBuildConfig2.getText());
+        assertEquals("fa", mBuildConfig2.getText());
     }
 
     @MediumTest
     public void testCodeOverlay() {
-        assertEquals("FA", mCodeOverlay2.getText());
+        assertEquals("fa", mCodeOverlay2.getText());
     }
 }
diff --git a/tests/flavors/src/instrumentTestFb/java/com/android/tests/flavors/MainActivityGroup2Test.java b/tests/flavors/src/instrumentTestFb/java/com/android/tests/flavors/MainActivityGroup2Test.java
index 6f92adf..f11b5ce 100644
--- a/tests/flavors/src/instrumentTestFb/java/com/android/tests/flavors/MainActivityGroup2Test.java
+++ b/tests/flavors/src/instrumentTestFb/java/com/android/tests/flavors/MainActivityGroup2Test.java
@@ -82,17 +82,17 @@
     public void testResOverlay() {
         // because this group has lower priority, we check that the resource from
         // this flavor is not used.
-        assertFalse("FB".equals(mResOverLay.getText()));
-        assertEquals("FB", mResOverLay2.getText());
+        assertFalse("fb".equals(mResOverLay.getText()));
+        assertEquals("fb", mResOverLay2.getText());
     }
 
     @MediumTest
     public void testBuildConfig() {
-        assertEquals("FB", mBuildConfig2.getText());
+        assertEquals("fb", mBuildConfig2.getText());
     }
 
     @MediumTest
     public void testCodeOverlay() {
-        assertEquals("FB", mCodeOverlay2.getText());
+        assertEquals("fb", mCodeOverlay2.getText());
     }
 }
diff --git a/tests/flavors/src/main/java/com/android/tests/flavors/MainActivity.java b/tests/flavors/src/main/java/com/android/tests/flavors/MainActivity.java
index 6968643..d768e1e 100644
--- a/tests/flavors/src/main/java/com/android/tests/flavors/MainActivity.java
+++ b/tests/flavors/src/main/java/com/android/tests/flavors/MainActivity.java
@@ -14,10 +14,10 @@
         TextView tv;
 
         tv = (TextView) findViewById(R.id.buildconfig1);
-        tv.setText(BuildConfig.GROUP1);
+        tv.setText(BuildConfig.FLAVOR1);
 
         tv = (TextView) findViewById(R.id.buildconfig2);
-        tv.setText(BuildConfig.GROUP2);
+        tv.setText(BuildConfig.FLAVOR2);
 
         tv = (TextView) findViewById(R.id.codeoverlay1);
         tv.setText(com.android.tests.flavors.group1.SomeClass.getString());