aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXavier Ducrohet <xav@android.com>2012-12-05 13:13:56 -0800
committerGerrit Code Review <noreply-gerritcodereview@google.com>2012-12-05 13:13:57 -0800
commit6ecf7a13a0dc2dbdfce71c83d86328ec6c80b6e3 (patch)
treecdc2831e9f4ed14f08aae925fdef0444908a8016
parentcb7a3df75e1fbef2f4de805f65008e0bbd085217 (diff)
parent131459f779b1a98bf354663298637589a2860fff (diff)
downloadsdk-6ecf7a13a0dc2dbdfce71c83d86328ec6c80b6e3.zip
sdk-6ecf7a13a0dc2dbdfce71c83d86328ec6c80b6e3.tar.gz
sdk-6ecf7a13a0dc2dbdfce71c83d86328ec6c80b6e3.tar.bz2
Merge "Support package conflicts between app and libs."
-rw-r--r--anttasks/src/com/android/ant/AaptExecTask.java148
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java93
-rw-r--r--files/ant/build.xml1
3 files changed, 210 insertions, 32 deletions
diff --git a/anttasks/src/com/android/ant/AaptExecTask.java b/anttasks/src/com/android/ant/AaptExecTask.java
index 2511500..f07cfad 100644
--- a/anttasks/src/com/android/ant/AaptExecTask.java
+++ b/anttasks/src/com/android/ant/AaptExecTask.java
@@ -19,19 +19,30 @@ package com.android.ant;
import com.android.SdkConstants;
import com.android.sdklib.internal.build.SymbolLoader;
import com.android.sdklib.internal.build.SymbolWriter;
+import com.android.xml.AndroidXPathFactory;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.ExecTask;
import org.apache.tools.ant.types.Path;
+import org.xml.sax.InputSource;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathExpressionException;
+
/**
* Task to execute aapt.
*
@@ -88,8 +99,9 @@ public final class AaptExecTask extends SingleDependencyTask {
private boolean mUseCrunchCache = false;
private int mVersionCode = 0;
private String mVersionName;
- private String mManifest;
+ private String mManifestFile;
private String mManifestPackage;
+ private String mOriginalManifestPackage;
private ArrayList<Path> mResources;
private String mAssets;
private String mAndroidJar;
@@ -223,7 +235,7 @@ public final class AaptExecTask extends SingleDependencyTask {
* @param manifest the value.
*/
public void setManifest(Path manifest) {
- mManifest = TaskHelper.checkSinglePath("manifest", manifest);
+ mManifestFile = TaskHelper.checkSinglePath("manifest", manifest);
}
/**
@@ -241,6 +253,18 @@ public final class AaptExecTask extends SingleDependencyTask {
}
/**
+ * Sets the original package name found in the manifest. This is the package name where
+ * the R class is created.
+ *
+ * This is merely a shortcut in case the package is known when calling the aapt task. If not
+ * provided (and needed) this task will recompute it.
+ * @param packageName the package name declared in the manifest.
+ */
+ public void setOriginalManifestPackage(String packageName) {
+ mOriginalManifestPackage = packageName;
+ }
+
+ /**
* Sets the value of the "resources" attribute.
* @param resources the value.
*
@@ -446,8 +470,8 @@ public final class AaptExecTask extends SingleDependencyTask {
sPathFactory);
// let's not forget the manifest as an input path (with no extension restrictions).
- if (mManifest != null) {
- inputPaths.add(new InputPath(new File(mManifest)));
+ if (mManifestFile != null) {
+ inputPaths.add(new InputPath(new File(mManifestFile)));
}
// Check to see if our dependencies have changed. If not, then skip
@@ -465,8 +489,8 @@ public final class AaptExecTask extends SingleDependencyTask {
sPathFactory);
// let's not forget the manifest as an input path.
- if (mManifest != null) {
- inputPaths.add(new InputPath(new File(mManifest)));
+ if (mManifestFile != null) {
+ inputPaths.add(new InputPath(new File(mManifestFile)));
}
// If we're here to generate a .ap_ file we need to use assets as an input path as well.
@@ -586,9 +610,9 @@ public final class AaptExecTask extends SingleDependencyTask {
}
// manifest location
- if (mManifest != null && mManifest.length() > 0) {
+ if (mManifestFile != null && mManifestFile.length() > 0) {
task.createArg().setValue("-M");
- task.createArg().setValue(mManifest);
+ task.createArg().setValue(mManifestFile);
}
// Rename manifest package
@@ -681,8 +705,9 @@ public final class AaptExecTask extends SingleDependencyTask {
if (!mNonConstantId && libPkgProp != null && !libPkgProp.isEmpty()) {
File rFile = new File(mBinFolder, SdkConstants.FN_RESOURCE_TEXT);
if (rFile.isFile()) {
- SymbolLoader symbolValues = new SymbolLoader(rFile);
- symbolValues.load();
+ // Load the full symbols from the full R.txt file.
+ SymbolLoader fullSymbols = new SymbolLoader(rFile);
+ fullSymbols.load();
// we have two props which contains list of items. Both items represent
// 2 data of a single property.
@@ -700,22 +725,105 @@ public final class AaptExecTask extends SingleDependencyTask {
mLibraryPackagesRefid, mLibraryRFileRefid));
}
- for (int i = 0 ; i < packages.length ; i++) {
- File libRFile = new File(rFiles[i]);
- if (libRFile.isFile()) {
- SymbolLoader symbols = new SymbolLoader(libRFile);
- symbols.load();
+ if (mOriginalManifestPackage == null) {
+ mOriginalManifestPackage = getPackageName(mManifestFile);
+ }
+
+ // simpler case of a single library
+ if (packages.length == 1) {
+ createRClass(fullSymbols, rFiles[0], packages[0]);
+ } else {
+
+ Map<String, String> libPackages = Maps.newHashMapWithExpectedSize(
+ packages.length);
+ Set<String> duplicatePackages = Sets.newHashSet();
+
+ // preprocessing to figure out if there are dups in the package names of
+ // the libraries
+ for (int i = 0 ; i < packages.length ; i++) {
+ String libPackage = packages[i];
+ if (mOriginalManifestPackage.equals(libPackage)) {
+ // skip libraries that have the same package name as the application.
+ continue;
+ }
+
+ String existingPkg = libPackages.get(libPackage);
+ if (existingPkg != null) {
+ // record the dup package and keep going, in case there are all the same
+ duplicatePackages.add(libPackage);
+ continue;
+ }
+
+ libPackages.put(libPackage, rFiles[i]);
+ }
- SymbolWriter writer = new SymbolWriter(mRFolder, packages[i],
- symbols, symbolValues);
- writer.write();
+ // check if we have duplicate but all files are the same.
+ if (duplicatePackages.size() > 0) {
+ // possible conflict!
+ // detect case of all libraries == same package.
+ if (duplicatePackages.size() == 1 && libPackages.size() == 1 &&
+ duplicatePackages.iterator().next().equals(libPackages.keySet().iterator().next())) {
+ // this is ok, all libraries have the same package.
+ // Make a copy of the full R class.
+ SymbolWriter writer = new SymbolWriter(mRFolder,
+ duplicatePackages.iterator().next(),
+ fullSymbols, fullSymbols);
+ writer.write();
+ } else {
+ StringBuilder sb = new StringBuilder();
+ sb.append("The following packages have been found to be used by two or more libraries:");
+ for (String pkg : duplicatePackages) {
+ sb.append("\n\t").append(pkg);
+ }
+ sb.append("\nNo libraries must share the same package, unless all libraries share the same packages.");
+ throw new BuildException(sb.toString());
+ }
+ } else {
+ // no dups, all libraries have different packages.
+ // Conflicts with the main package have been removed already.
+ // Just process all the libraries from the list where we removed
+ // libs that had the same package as the app.
+ for (Entry<String, String> lib : libPackages.entrySet()) {
+ createRClass(fullSymbols, lib.getValue(), lib.getKey());
+ }
}
}
}
}
- } catch (IOException e) {
- throw new BuildException(e);
+ } catch (Exception e) {
+ // HACK alert.
+ // in order for this step to happen again when this part fails, we delete
+ // the dependency file.
+ File f = new File(mRFolder, "R.java.d");
+ f.delete();
+
+ throw (e instanceof BuildException) ? (BuildException)e : new BuildException(e);
}
+ }
+
+ private void createRClass(SymbolLoader fullSymbols, String libRTxtFile, String libPackage)
+ throws IOException {
+ File libSymbolFile = new File(libRTxtFile);
+ if (libSymbolFile.isFile()) {
+ SymbolLoader libSymbols = new SymbolLoader(libSymbolFile);
+ libSymbols.load();
+
+ SymbolWriter writer = new SymbolWriter(mRFolder, libPackage, libSymbols, fullSymbols);
+ writer.write();
+ }
+ }
+ private String getPackageName(String manifest) {
+ XPath xpath = AndroidXPathFactory.newXPath();
+
+ try {
+ String s = xpath.evaluate("/manifest/@package",
+ new InputSource(new FileInputStream(manifest)));
+ return s;
+ } catch (XPathExpressionException e) {
+ throw new BuildException(e);
+ } catch (FileNotFoundException e) {
+ throw new BuildException(e);
+ }
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java
index 25b16e4..ba23c95 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java
@@ -56,6 +56,8 @@ import com.android.utils.ILogger;
import com.android.utils.Pair;
import com.android.xml.AndroidManifest;
import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
@@ -78,6 +80,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import javax.xml.parsers.ParserConfigurationException;
@@ -1156,18 +1159,71 @@ public class PreCompilerBuilder extends BaseBuilder {
File rFile = new File(outputFolder, SdkConstants.FN_RESOURCE_TEXT);
// if the project has no resources, the file could not exist.
if (rFile.isFile()) {
- SymbolLoader symbolValues = new SymbolLoader(rFile);
- symbolValues.load();
-
- for (Pair<File, String> libData : libRFiles) {
- File libRFile = libData.getFirst();
- if (libRFile.isFile()) {
- SymbolLoader symbols = new SymbolLoader(libRFile);
- symbols.load();
-
- SymbolWriter writer = new SymbolWriter(osOutputPath,
- libData.getSecond(), symbols, symbolValues);
- writer.write();
+ // Load the full symbols from the full R.txt file.
+ SymbolLoader fullSymbols = new SymbolLoader(rFile);
+ fullSymbols.load();
+
+ // simpler case of a single library
+ if (libRFiles.size() == 1) {
+ Pair<File, String> lib = libRFiles.get(0);
+ createRClass(fullSymbols, lib.getFirst(), lib.getSecond(), osOutputPath);
+
+ } else {
+ Map<String, File> libPackages = Maps.newHashMapWithExpectedSize(
+ libRFiles.size());
+ Set<String> duplicatePackages = Sets.newHashSet();
+
+ // preprocessing to figure out if there are dups in the package names of
+ // the libraries
+ for (Pair<File, String> lib : libRFiles) {
+ String libPackage = lib.getSecond();
+ File existingPkg = libPackages.get(libPackage);
+ if (existingPkg != null) {
+ // record the dup package and keep going, in case there are all
+ // the same
+ duplicatePackages.add(libPackage);
+ continue;
+ }
+
+ libPackages.put(libPackage, lib.getFirst());
+ }
+
+ // check if we have duplicate but all files are the same.
+ if (duplicatePackages.size() > 0) {
+ // possible conflict!
+ // detect case of all libraries == same package.
+ if (duplicatePackages.size() == 1 && libPackages.size() == 1 &&
+ duplicatePackages.iterator().next().equals(libPackages.keySet().iterator().next())) {
+ // this is ok, all libraries have the same package.
+ // Make a copy of the full R class.
+ SymbolWriter writer = new SymbolWriter(osOutputPath,
+ duplicatePackages.iterator().next(),
+ fullSymbols, fullSymbols);
+ writer.write();
+ } else {
+ StringBuilder sb = new StringBuilder();
+ sb.append("The following packages have been found to be used by two or more libraries:");
+ for (String pkg : duplicatePackages) {
+ sb.append("\n\t").append(pkg);
+ }
+ sb.append("\nNo libraries must share the same package, unless all libraries share the same packages.");
+
+ String msg = sb.toString();
+ markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR);
+
+ AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project,
+ msg);
+
+ throw new AbortBuildException();
+ }
+ } else {
+ // no dups, all libraries have different packages.
+ // Conflicts with the main package have been removed already.
+ // Just process all the libraries.
+ for (Pair<File, String> lib : libRFiles) {
+ createRClass(fullSymbols, lib.getFirst(), lib.getSecond(),
+ osOutputPath);
+ }
}
}
}
@@ -1227,6 +1283,19 @@ public class PreCompilerBuilder extends BaseBuilder {
}
}
+ private void createRClass(SymbolLoader fullSymbols, File libRTxtFile, String libPackage,
+ String osOutputPath) throws IOException {
+ if (libRTxtFile.isFile()) {
+ SymbolLoader libSymbols = new SymbolLoader(libRTxtFile);
+ libSymbols.load();
+
+ SymbolWriter writer = new SymbolWriter(osOutputPath, libPackage, libSymbols,
+ fullSymbols);
+ writer.write();
+ }
+ }
+
+
/**
* Creates a relative {@link IPath} from a java package.
* @param javaPackageName the java package.
diff --git a/files/ant/build.xml b/files/ant/build.xml
index acba923..e3ae78a 100644
--- a/files/ant/build.xml
+++ b/files/ant/build.xml
@@ -674,6 +674,7 @@
command="package"
verbose="${verbose}"
manifest="${out.manifest.abs.file}"
+ originalManifestPackage="${project.app.package}"
androidjar="${project.target.android.jar}"
rfolder="${gen.absolute.dir}"
nonConstantId="${android.library}"