aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--anttasks/src/com/android/ant/AaptExecTask.java47
-rw-r--r--anttasks/src/com/android/ant/BuildConfigTask.java68
-rw-r--r--anttasks/src/com/android/ant/BuildTypedTask.java63
-rw-r--r--anttasks/src/com/android/ant/DependencyGraph.java26
-rw-r--r--anttasks/src/com/android/ant/DexExecTask.java3
-rw-r--r--anttasks/src/com/android/ant/InputPath.java20
-rw-r--r--anttasks/src/com/android/ant/SingleDependencyTask.java51
-rw-r--r--files/ant/build.xml113
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/build/ApkBuilder.java2
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/internal/build/BuildConfig.template6
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/internal/build/BuildConfigGenerator.java138
11 files changed, 478 insertions, 59 deletions
diff --git a/anttasks/src/com/android/ant/AaptExecTask.java b/anttasks/src/com/android/ant/AaptExecTask.java
index 45adc7c..8731732 100644
--- a/anttasks/src/com/android/ant/AaptExecTask.java
+++ b/anttasks/src/com/android/ant/AaptExecTask.java
@@ -25,6 +25,7 @@ import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Set;
/**
* Task to execute aapt.
@@ -95,6 +96,46 @@ public final class AaptExecTask extends SingleDependencyTask {
private boolean mNonConstantId;
/**
+ * Input path that ignores the same file that aapt does.
+ */
+ private static class ResFolderInputPath extends InputPath {
+ public ResFolderInputPath(File file, Set<String> extensionsToCheck) {
+ super(file, extensionsToCheck);
+ }
+
+ @Override
+ public boolean ignores(File file) {
+ String name = file.getName();
+ char firstChar = name.charAt(0);
+
+ if (firstChar == '.' || (firstChar == '_' && file.isDirectory()) ||
+ name.charAt(name.length()-1) == '~') {
+ return true;
+ }
+
+ if ("CVS".equals(name) ||
+ "thumbs.db".equalsIgnoreCase(name) ||
+ "picasa.ini".equalsIgnoreCase(name)) {
+ return true;
+ }
+
+ String ext = getExtension(name);
+ if ("scc".equalsIgnoreCase(ext)) {
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ private final static InputPathFactory sPathFactory = new InputPathFactory() {
+
+ public InputPath createPath(File file, Set<String> extensionsToCheck) {
+ return new ResFolderInputPath(file, extensionsToCheck);
+ }
+ };
+
+ /**
* Sets the value of the "executable" attribute.
* @param executable the value.
*/
@@ -351,7 +392,8 @@ public final class AaptExecTask extends SingleDependencyTask {
if (generateRClass) {
// in this case we only want to run aapt if an XML file was touched, or if any
// file is added/removed
- List<InputPath> inputPaths = getInputPaths(paths, Collections.singleton("xml"));
+ List<InputPath> inputPaths = getInputPaths(paths, Collections.singleton("xml"),
+ sPathFactory);
// let's not forget the manifest as an input path (with no extension restrictions).
if (mManifest != null) {
@@ -369,7 +411,8 @@ public final class AaptExecTask extends SingleDependencyTask {
} else {
// in this case we want to run aapt if any file was updated/removed/added in any of the
// input paths
- List<InputPath> inputPaths = getInputPaths(paths, null /*extensionsToCheck*/);
+ List<InputPath> inputPaths = getInputPaths(paths, null /*extensionsToCheck*/,
+ sPathFactory);
// let's not forget the manifest as an input path.
if (mManifest != null) {
diff --git a/anttasks/src/com/android/ant/BuildConfigTask.java b/anttasks/src/com/android/ant/BuildConfigTask.java
new file mode 100644
index 0000000..08f91e9
--- /dev/null
+++ b/anttasks/src/com/android/ant/BuildConfigTask.java
@@ -0,0 +1,68 @@
+/*
+ * 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.ant;
+
+import com.android.sdklib.internal.build.BuildConfigGenerator;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Path;
+
+import java.io.IOException;
+
+public class BuildConfigTask extends BuildTypedTask {
+
+ private String mGenFolder;
+ private String mAppPackage;
+
+ public void setGenFolder(Path path) {
+ mGenFolder = TaskHelper.checkSinglePath("genFolder", path);
+ }
+
+ public void setPackage(String appPackage) {
+ mAppPackage = appPackage;
+ }
+
+
+ @Override
+ public void execute() throws BuildException {
+ if (mGenFolder == null) {
+ throw new BuildException("Missing attribute genFolder");
+ }
+ if (mAppPackage == null) {
+ throw new BuildException("Missing attribute package");
+ }
+
+ if (hasBuildTypeChanged()) {
+ if (isNewBuild()) {
+ System.out.println("Generating BuildConfig class.");
+ } else {
+ System.out.println("Build type changed: Generating new BuildConfig class.");
+ }
+ BuildConfigGenerator generator = new BuildConfigGenerator(
+ mGenFolder, mAppPackage,
+ Boolean.parseBoolean(getBuildType()));
+
+ try {
+ generator.generate();
+ } catch (IOException e) {
+ throw new BuildException("Failed to create BuildConfig class", e);
+ }
+ } else {
+ System.out.println("No need to generate new BuildConfig.");
+ }
+ }
+}
diff --git a/anttasks/src/com/android/ant/BuildTypedTask.java b/anttasks/src/com/android/ant/BuildTypedTask.java
new file mode 100644
index 0000000..c697bac
--- /dev/null
+++ b/anttasks/src/com/android/ant/BuildTypedTask.java
@@ -0,0 +1,63 @@
+/*
+ * 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.ant;
+
+import org.apache.tools.ant.Task;
+
+/**
+ * Base class for tasks that should exec when the build type change.
+ */
+public abstract class BuildTypedTask extends Task {
+
+ private String mPreviousBuildType;
+ private String mBuildType;
+
+ /** Sets the current build type */
+ public void setBuildType(String buildType) {
+ mBuildType = buildType;
+ }
+
+ /** Sets the previous build type */
+ public void setPreviousBuildType(String previousBuildType) {
+ mPreviousBuildType = previousBuildType;
+ }
+
+ protected String getBuildType() {
+ return mBuildType;
+ }
+
+ /**
+ * Returns if it is a new build. If the built type is not input
+ * from the XML, this always returns true.
+ * A build type is defined by having an empty previousBuildType.
+ */
+ protected boolean isNewBuild() {
+ return mBuildType == null || mPreviousBuildType.length() == 0;
+ }
+
+ /**
+ * Returns true if the build type changed.
+ */
+ protected boolean hasBuildTypeChanged() {
+ // no build type? return false as the feature is simply not used
+ if (mBuildType == null && mPreviousBuildType == null) {
+ return false;
+ }
+
+ return mBuildType.equals(mPreviousBuildType) == false;
+ }
+}
diff --git a/anttasks/src/com/android/ant/DependencyGraph.java b/anttasks/src/com/android/ant/DependencyGraph.java
index 1885c17..8671359 100644
--- a/anttasks/src/com/android/ant/DependencyGraph.java
+++ b/anttasks/src/com/android/ant/DependencyGraph.java
@@ -35,6 +35,8 @@ import java.util.Set;
*/
public class DependencyGraph {
+ private final static boolean DEBUG = false;
+
private static enum DependencyStatus {
NONE, NEW_FILE, UPDATED_FILE, MISSING_FILE, ERROR;
}
@@ -189,6 +191,9 @@ public class DependencyGraph {
mPrereqs = new HashSet<File>(prereqs.length);
for (String path : prereqs) {
if (path.length() > 0) {
+ if (DEBUG) {
+ System.out.println("PREREQ: " + path);
+ }
File f = new File(path);
if (mFirstPrereq == null) {
mFirstPrereq = f;
@@ -290,12 +295,19 @@ public class DependencyGraph {
// files to go through manually
if (mPrereqs.remove(file) == false) {
// turns out this is a new file!
+
+ if (DEBUG) {
+ System.out.println("NEW FILE: " + file.getAbsolutePath());
+ }
return DependencyStatus.NEW_FILE;
} else {
// check the time stamp on this file if it's a file we care about based what the
// input folder decides.
if (inputFolder.checksForModification(file)) {
if (file.lastModified() > oldestTarget) {
+ if (DEBUG) {
+ System.out.println("UPDATED FILE: " + file.getAbsolutePath());
+ }
return DependencyStatus.UPDATED_FILE;
}
}
@@ -319,6 +331,9 @@ public class DependencyGraph {
// Loop through our prereq files and make sure they still exist
for (File prereq : mPrereqs) {
if (prereq.exists() == false) {
+ if (DEBUG) {
+ System.out.println("MISSING FILE: " + prereq.getAbsolutePath());
+ }
return DependencyStatus.MISSING_FILE;
}
@@ -336,6 +351,10 @@ public class DependencyGraph {
// check if we need to check this type of file, and if yes, check it.
if (input.checksForModification(prereq)) {
if (prereq.lastModified() > oldestTarget) {
+ if (DEBUG) {
+ System.out.println(
+ "UPDATED FILE: " + prereq.getAbsolutePath());
+ }
return DependencyStatus.UPDATED_FILE;
}
}
@@ -345,6 +364,10 @@ public class DependencyGraph {
if (prereq.equals(inputFile)) {
if (input.checksForModification(prereq)) {
if (prereq.lastModified() > oldestTarget) {
+ if (DEBUG) {
+ System.out.println(
+ "UPDATED FILE: " + prereq.getAbsolutePath());
+ }
return DependencyStatus.UPDATED_FILE;
}
}
@@ -354,6 +377,9 @@ public class DependencyGraph {
} else {
// no input? we consider all files.
if (prereq.lastModified() > oldestTarget) {
+ if (DEBUG) {
+ System.out.println("UPDATED FILE: " + prereq.getAbsolutePath());
+ }
return DependencyStatus.UPDATED_FILE;
}
}
diff --git a/anttasks/src/com/android/ant/DexExecTask.java b/anttasks/src/com/android/ant/DexExecTask.java
index 6be0a98..2d9479e 100644
--- a/anttasks/src/com/android/ant/DexExecTask.java
+++ b/anttasks/src/com/android/ant/DexExecTask.java
@@ -129,7 +129,8 @@ public class DexExecTask extends SingleDependencyTask {
String depFile = mOutput + ".d";
// get InputPath with no extension restrictions
- List<InputPath> inputPaths = getInputPaths(paths, null /*extensionsToCheck*/);
+ List<InputPath> inputPaths = getInputPaths(paths, null /*extensionsToCheck*/,
+ null /*factory*/);
if (initDependencies(depFile, inputPaths) && dependenciesHaveChanged() == false) {
System.out.println(
diff --git a/anttasks/src/com/android/ant/InputPath.java b/anttasks/src/com/android/ant/InputPath.java
index 3327385..b1a98b5 100644
--- a/anttasks/src/com/android/ant/InputPath.java
+++ b/anttasks/src/com/android/ant/InputPath.java
@@ -72,23 +72,33 @@ public class InputPath {
* @return true if the file or folder are ignored.
*/
public boolean ignores(File file) {
- return false;
+ // always ignore hidden files/folders.
+ return file.getName().startsWith(".") == false;
}
/**
* Gets the extension (if present) on a file by looking at the filename
- * @param file the file to get the extension of
+ * @param file the file to get the extension from
* @return the extension if present, or the empty string if the filename doesn't have
* and extension.
*/
protected static String getExtension(File file) {
- String filename = file.getName();
- int index = filename.lastIndexOf('.');
+ return getExtension(file.getName());
+ }
+
+ /**
+ * Gets the extension (if present) on a file by looking at the filename
+ * @param fileName the filename to get the extension from
+ * @return the extension if present, or the empty string if the filename doesn't have
+ * and extension.
+ */
+ protected static String getExtension(String fileName) {
+ int index = fileName.lastIndexOf('.');
if (index == -1) {
return "";
}
// Don't include the leading '.' in the extension
- return filename.substring(index + 1);
+ return fileName.substring(index + 1);
}
}
diff --git a/anttasks/src/com/android/ant/SingleDependencyTask.java b/anttasks/src/com/android/ant/SingleDependencyTask.java
index dc3e15d..926e59c 100644
--- a/anttasks/src/com/android/ant/SingleDependencyTask.java
+++ b/anttasks/src/com/android/ant/SingleDependencyTask.java
@@ -17,7 +17,6 @@
package com.android.ant;
import org.apache.tools.ant.BuildException;
-import org.apache.tools.ant.Task;
import java.io.File;
import java.io.FileNotFoundException;
@@ -29,21 +28,21 @@ import java.util.Set;
/**
* A base class for ant tasks that use a single dependency files to control (re)execution.
*/
-public abstract class SingleDependencyTask extends Task {
+public abstract class SingleDependencyTask extends BuildTypedTask {
private DependencyGraph mDependencies;
- private String mPreviousBuildType;
- private String mBuildType;
- public void setPreviousBuildType(String previousBuildType) {
- mPreviousBuildType = previousBuildType;
- }
+ protected abstract String getExecTaskName();
- public void setBuildType(String buildType) {
- mBuildType = buildType;
+ protected interface InputPathFactory {
+ InputPath createPath(File file, Set<String> extensionsToCheck);
}
- protected abstract String getExecTaskName();
+ private final static InputPathFactory sDefaultFactory = new InputPathFactory() {
+ public InputPath createPath(File file, Set<String> extensionsToCheck) {
+ return new InputPath(file, extensionsToCheck);
+ }
+ };
/**
* Creates a list of {@link InputPath} from a list of {@link File} and an optional list of
@@ -55,11 +54,15 @@ public abstract class SingleDependencyTask extends Task {
* @return a list of {@link InputPath}
*/
protected static List<InputPath> getInputPaths(List<File> paths,
- Set<String> extensionsToCheck) {
+ Set<String> extensionsToCheck, InputPathFactory factory) {
List<InputPath> result = new ArrayList<InputPath>(paths.size());
+ if (factory == null ) {
+ factory = sDefaultFactory;
+ }
+
for (File f : paths) {
- result.add(new InputPath(f, extensionsToCheck));
+ result.add(factory.createPath(f, extensionsToCheck));
}
return result;
@@ -73,7 +76,7 @@ public abstract class SingleDependencyTask extends Task {
* @return true if the dependency graph was successfully initialized
*/
protected boolean initDependencies(String dependencyFile, List<InputPath> inputPaths) {
- if (mBuildType != null && mBuildType.equals(mPreviousBuildType) == false) {
+ if (hasBuildTypeChanged()) {
// we don't care about deps, we need to execute the task no matter what.
return true;
}
@@ -93,15 +96,19 @@ public abstract class SingleDependencyTask extends Task {
* have changed since the last run
*/
protected boolean dependenciesHaveChanged() {
- if (mBuildType != null && mBuildType.equals(mPreviousBuildType) == false) {
- String execName = getExecTaskName();
- if (execName == null) {
- System.out.println(
- "Current build type is different than previous build: forced task run.");
- } else {
- System.out.println(
- "Current build type is different than previous build: forced " +
- execName + " run.");
+ if (hasBuildTypeChanged()) {
+ // if this is not a new build, display that build type change is forcing running
+ // the task.
+ if (isNewBuild() == false) {
+ String execName = getExecTaskName();
+ if (execName == null) {
+ System.out.println(
+ "Current build type is different than previous build: forced task run.");
+ } else {
+ System.out.println(
+ "Current build type is different than previous build: forced " +
+ execName + " run.");
+ }
}
return true;
}
diff --git a/files/ant/build.xml b/files/ant/build.xml
index cc8f398..91dbb1f 100644
--- a/files/ant/build.xml
+++ b/files/ant/build.xml
@@ -7,7 +7,7 @@
regular projects, library projects, or test projects.
At the beginning of the file is a list of properties that can be overridden
- by adding them to your build.properties (properties are immutable, so their
+ by adding them to your ant.properties (properties are immutable, so their
first definition sticks and is never changed).
Follows:
@@ -23,7 +23,9 @@
- help target
-->
- <!-- ********** Overrideable Properties ********** -->
+ <!-- ******************************************************* -->
+ <!-- *************** Overrideable Properties *************** -->
+ <!-- ******************************************************* -->
<!-- You can override these values in your build.xml or build.properties.
Overriding any other properties may result in broken build. -->
@@ -52,7 +54,9 @@
<!-- Verbosity -->
<property name="verbose" value="false" />
- <!-- ********** Custom Tasks ********** -->
+ <!-- ******************************************************* -->
+ <!-- ********************* Custom Tasks ******************** -->
+ <!-- ******************************************************* -->
<!-- jar file from where the tasks are loaded -->
<path id="android.antlibs">
@@ -76,6 +80,10 @@
classname="com.android.ant.RenderScriptTask"
classpathref="android.antlibs" />
+ <taskdef name="buildconfig"
+ classname="com.android.ant.BuildConfigTask"
+ classpathref="android.antlibs" />
+
<taskdef name="dex"
classname="com.android.ant.DexExecTask"
classpathref="android.antlibs" />
@@ -106,7 +114,9 @@
<!-- End of emma configuration -->
- <!-- ********** Other Properties ********** -->
+ <!-- ******************************************************* -->
+ <!-- ******************* Other Properties ****************** -->
+ <!-- ******************************************************* -->
<!-- overriding these properties may break the build
unless the whole file is updated -->
@@ -174,7 +184,9 @@
<!-- properties for packaging -->
<property name="build.packaging.nocrunch" value="true" />
- <!-- ********** Macros ********** -->
+ <!-- ******************************************************* -->
+ <!-- ************************ Macros *********************** -->
+ <!-- ******************************************************* -->
<!-- macro to do a task on if project.is.library is false.
elseText attribute is displayed otherwise -->
@@ -244,9 +256,7 @@
<dex executable="${dx}"
output="${intermediate.dex.file}"
nolocals="@{nolocals}"
- verbose="${verbose}"
- previousBuildType="${build.last.target}"
- buildType="${build.target}">
+ verbose="${verbose}">
<path path="${out.dex.input.absolute.dir}"/>
<path refid="out.dex.jar.input.ref" />
<external-libs />
@@ -351,7 +361,9 @@
</sequential>
</macrodef>
- <!-- ********** Build Targets ********** -->
+ <!-- ******************************************************* -->
+ <!-- ******************** Build Targets ******************** -->
+ <!-- ******************************************************* -->
<!-- this target simply force running -setup making
the project info be read. To be used as
@@ -444,13 +456,12 @@
<!-- read the previous build mode -->
<property file="${out.build.prop.file}" />
- <!-- if empty the prop won't be set, so set it to the current target
- to provide a default value equal to the current build -->
- <property name="build.last.target" value="${build.target}" />
- <!-- also set the default value for whether the build is instrumented -->
- <property name="build.last.is.instrumented" value="${build.is.instrumented}" />
- <property name="build.last.is.packaging.debug" value="${build.is.packaging.debug}" />
- <property name="build.last.is.signing.debug" value="${build.is.signing.debug}" />
+ <!-- if empty the props won't be set, meaning it's a new build.
+ To force a build, set the prop to empty values. -->
+ <property name="build.last.target" value="" />
+ <property name="build.last.is.instrumented" value="" />
+ <property name="build.last.is.packaging.debug" value="" />
+ <property name="build.last.is.signing.debug" value="" />
<!-- compile the libraries if any -->
<if>
@@ -502,20 +513,39 @@
<path refid="project.libraries.jars" />
</path>
- <!-- special case for instrumented: if the previous build was
- instrumented but not this one, clear out the compiled code -->
+ <!-- If the "debug" build type changed, clear out the compiled code.
+ This is to make sure the new BuildConfig.DEBUG value is picked up
+ as javac can't deal with this type of change in its dependency computation. -->
<if>
<condition>
<and>
- <istrue value="${build.last.is.instrumented}" />
- <isfalse value="${build.is.instrumented}" />
+ <length string="${build.last.is.packaging.debug}" trim="true" when="greater" length="0" />
+ <not><equals
+ arg1="${build.is.packaging.debug}"
+ arg2="${build.last.is.packaging.debug}" /></not>
</and>
</condition>
<then>
- <echo>Switching from instrumented to non-instrumented build.</echo>
- <echo>Deleting previous compilation output:</echo>
+ <echo>Switching between debug and non debug build: Deleting previous compilation output...</echo>
<delete dir="${out.classes.absolute.dir}" verbose="${verbose}" />
</then>
+ <else>
+ <!-- Else, we may still need to clean the code, for another reason.
+ special case for instrumented: if the previous build was
+ instrumented but not this one, clear out the compiled code -->
+ <if>
+ <condition>
+ <and>
+ <istrue value="${build.last.is.instrumented}" />
+ <isfalse value="${build.is.instrumented}" />
+ </and>
+ </condition>
+ <then>
+ <echo>Switching from instrumented to non-instrumented build: Deleting previous compilation output...</echo>
+ <delete dir="${out.classes.absolute.dir}" verbose="${verbose}" />
+ </then>
+ </if>
+ </else>
</if>
<echo>Creating output directories if needed...</echo>
@@ -569,6 +599,17 @@
<res path="${out.res.absolute.dir}" />
<res path="${resource.absolute.dir}" />
</aapt>
+
+ <echo>----------</echo>
+ <echo>Handling BuildConfig class...</echo>
+ <xpath input="AndroidManifest.xml" expression="/manifest/@package"
+ output="manifest.package" />
+ <buildconfig
+ genFolder="${gen.absolute.dir}"
+ package="${manifest.package}"
+ buildType="${build.is.packaging.debug}"
+ previousBuildType="${build.last.is.packaging.debug}"/>
+
</do-only-if-manifest-hasCode>
</target>
@@ -593,7 +634,7 @@
</condition>
<javac encoding="${java.encoding}"
source="${java.source}" target="${java.target}"
- debug="true" extdirs=""
+ debug="true" extdirs="" includeantruntime="false"
destdir="${out.classes.absolute.dir}"
bootclasspathref="android.target.classpath"
verbose="${verbose}"
@@ -817,7 +858,9 @@
message="Cannot run two different modes at the same time. If you are running more than one debug/release/instrument type targets, call them from different Ant calls." />
</target>
- <!-- ********** Debug specific targets ********** -->
+ <!-- ******************************************************* -->
+ <!-- **************** Debug specific targets *************** -->
+ <!-- ******************************************************* -->
<target name="-set-debug-files" depends="-set-mode-check">
@@ -863,7 +906,9 @@
</target>
- <!-- ********** Release specific targets ********** -->
+ <!-- ******************************************************* -->
+ <!-- *************** Release specific targets ************** -->
+ <!-- ******************************************************* -->
<!-- called through target 'release'. Only executed if the keystore and
key alias are known but not their password. -->
@@ -974,7 +1019,9 @@
<record-build-info />
</target>
- <!-- ********** Instrumented specific targets ********** -->
+ <!-- ******************************************************* -->
+ <!-- ************ Instrumented specific targets ************ -->
+ <!-- ******************************************************* -->
<!-- These targets are specific for the project under test when it
gets compiled by the test projects in a way that will make it
@@ -1001,7 +1048,9 @@
<record-build-info />
</target>
- <!-- ********** Test project specific targets ********** -->
+ <!-- ******************************************************* -->
+ <!-- ************ Test project specific targets ************ -->
+ <!-- ******************************************************* -->
<!-- enable code coverage -->
<target name="emma">
@@ -1089,7 +1138,9 @@
</target>
- <!-- ********** Install/uninstall specific targets ********** -->
+ <!-- ******************************************************* -->
+ <!-- ********** Install/uninstall specific targets ********* -->
+ <!-- ******************************************************* -->
<target name="install"
description="Installs the newly build package. Must be used in conjunction with a build target
@@ -1107,7 +1158,7 @@
<resourceexists>
<file file="${out.final.file}"/>
</resourceexists>
- </condition>
+ </condition>
<then>
<echo>Installing ${out.final.file} onto default emulator or device...</echo>
<exec executable="${adb}" failonerror="true">
@@ -1198,6 +1249,10 @@
</target>
+ <!-- ******************************************************* -->
+ <!-- ************************* Help ************************ -->
+ <!-- ******************************************************* -->
+
<target name="help">
<!-- displays starts at col 13
|13 80| -->
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/build/ApkBuilder.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/build/ApkBuilder.java
index a475e1b..774d9f4 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/build/ApkBuilder.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/build/ApkBuilder.java
@@ -949,6 +949,8 @@ public final class ApkBuilder implements IArchiveBuilder {
"class".equalsIgnoreCase(extension) == false && // Java class files
"scc".equalsIgnoreCase(extension) == false && // VisualSourceSafe
"swp".equalsIgnoreCase(extension) == false && // vi swap file
+ "thumbs.db".equalsIgnoreCase(fileName) == false && // image index file
+ "picasa.ini".equalsIgnoreCase(fileName) == false && // image index file
"package.html".equalsIgnoreCase(fileName) == false && // Javadoc
"overview.html".equalsIgnoreCase(fileName) == false; // Javadoc
}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/build/BuildConfig.template b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/build/BuildConfig.template
new file mode 100644
index 0000000..0344b55
--- /dev/null
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/build/BuildConfig.template
@@ -0,0 +1,6 @@
+/** Automatically generated file. DO NOT MODIFY */
+package #PACKAGE#;
+
+public final class BuildConfig {
+ public final static boolean DEBUG = #DEBUG#;
+} \ No newline at end of file
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/build/BuildConfigGenerator.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/build/BuildConfigGenerator.java
new file mode 100644
index 0000000..fb84bfd
--- /dev/null
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/build/BuildConfigGenerator.java
@@ -0,0 +1,138 @@
+/*
+ * 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.sdklib.internal.build;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * 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 PH_PACKAGE = "#PACKAGE#";
+ private final static String PH_DEBUG = "#DEBUG#";
+
+ private final String mGenFolder;
+ private final String mAppPackage;
+ private final boolean mDebug;
+
+ /**
+ * 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(String genFolder, String appPackage, boolean debug) {
+ mGenFolder = genFolder;
+ mAppPackage = appPackage;
+ mDebug = debug;
+ }
+
+ /**
+ * Generates the BuildConfig class.
+ */
+ public void generate() throws IOException {
+ String template = readEmbeddedTextFile("BuildConfig.template");
+
+ Map<String, String> map = new HashMap<String, String>();
+ map.put(PH_PACKAGE, mAppPackage);
+ map.put(PH_DEBUG, Boolean.toString(mDebug));
+
+ String content = replaceParameters(template, map);
+
+ File genFolder = new File(mGenFolder);
+ File pkgFolder = new File(genFolder, mAppPackage.replaceAll("\\.", File.separator));
+ if (pkgFolder.isDirectory() == false) {
+ pkgFolder.mkdirs();
+ }
+
+ File buildConfigJava = new File(pkgFolder, "BuildConfig.java");
+ writeFile(buildConfigJava, content);
+ }
+
+ /**
+ * Reads and returns the content of a text file embedded in the jar file.
+ * @param filepath the file path to the text file
+ * @return null if the file could not be read
+ * @throws IOException
+ */
+ private String readEmbeddedTextFile(String filepath) throws IOException {
+ InputStream is = BuildConfigGenerator.class.getResourceAsStream(filepath);
+ if (is != null) {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+
+ String line;
+ StringBuilder total = new StringBuilder(reader.readLine());
+ while ((line = reader.readLine()) != null) {
+ total.append('\n');
+ total.append(line);
+ }
+
+ return total.toString();
+ }
+
+ // this really shouldn't happen unless the sdklib packaging is broken.
+ throw new IOException("BuildConfig template is missing!");
+ }
+
+ private void writeFile(File file, String content) throws IOException {
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(file);
+ InputStream source = new ByteArrayInputStream(content.getBytes("UTF-8"));
+
+ byte[] buffer = new byte[1024];
+ int count = 0;
+ while ((count = source.read(buffer)) != -1) {
+ fos.write(buffer, 0, count);
+ }
+ } finally {
+ if (fos != null) {
+ fos.close();
+ }
+ }
+ }
+
+ /**
+ * Replaces placeholders found in a string with values.
+ *
+ * @param str the string to search for placeholders.
+ * @param parameters a map of <placeholder, Value> to search for in the string
+ * @return A new String object with the placeholder replaced by the values.
+ */
+ private String replaceParameters(String str, Map<String, String> parameters) {
+
+ for (Entry<String, String> entry : parameters.entrySet()) {
+ String value = entry.getValue();
+ if (value != null) {
+ str = str.replaceAll(entry.getKey(), value);
+ }
+ }
+
+ return str;
+ }
+}