aboutsummaryrefslogtreecommitdiffstats
path: root/eclipse/plugins/com.android.ide.eclipse.adt
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt')
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/gscripts/android.widget.RelativeLayout.groovy49
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AndroidConstants.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/MultiApkExportAction.java15
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkBuilder.java9
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkBuilderHelper.java494
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkDeltaVisitor.java4
6 files changed, 188 insertions, 385 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/gscripts/android.widget.RelativeLayout.groovy b/eclipse/plugins/com.android.ide.eclipse.adt/gscripts/android.widget.RelativeLayout.groovy
index 02606d9..4bac2d8 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/gscripts/android.widget.RelativeLayout.groovy
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/gscripts/android.widget.RelativeLayout.groovy
@@ -460,21 +460,23 @@ public class AndroidWidgetRelativeLayoutRule extends BaseLayout {
int x = r.x + 5;
int y = r.y + r.h + 5;
int h = gc.getFontHeight();
+
String id = null;
if (data.child) {
id = data.child.getStringAttr(ANDROID_URI, ATTR_ID);
}
- data.curr.attr.each {
- String s = it;
+
+ for (s in data.curr.attr) {
if (id) s = "$s=$id";
gc.drawString(s, x, y);
y += h;
}
+ gc.setLineStyle(IGraphics.LineStyle.LINE_SOLID);
+ gc.setLineWidth(2);
+
def mark = data.curr.get("mark");
if (mark) {
- gc.setLineStyle(IGraphics.LineStyle.LINE_SOLID);
- gc.setLineWidth(2);
def black = gc.registerColor(0);
gc.setForeground(black);
@@ -484,21 +486,38 @@ public class AndroidWidgetRelativeLayoutRule extends BaseLayout {
gc.drawLine(x + 10, y - 10, x - 10, y + 10);
gc.drawOval(x - 10, y - 10, x + 10, y + 10);
- Rect be = elements[0].getBounds();
+ } else {
- if (be.isValid()) {
- // At least the first element has a bound. Draw rectangles
- // for all dropped elements with valid bounds, offset at
- // the drop point.
+ r = data.curr.rect;
+ x = r.x + r.w / 2;
+ y = r.y + r.h / 2;
+ }
- int offsetX = x - be.x;
- int offsetY = y - be.y;
+ Rect be = elements[0].getBounds();
- gc.setForeground(gc.registerColor(0x00FFFF00));
+ if (be.isValid()) {
+ // At least the first element has a bound. Draw rectangles
+ // for all dropped elements with valid bounds, offset at
+ // the drop point.
- for (element in elements) {
- drawElement(gc, element, offsetX, offsetY);
- }
+ int offsetX = x - be.x;
+ int offsetY = y - be.y;
+
+ if ("alignTop" in data.curr.attr && "alignBottom" in data.curr.attr) {
+ offsetY -= be.h / 2;
+ } else if ("above" in data.curr.attr || "alignTop" in data.curr.attr) {
+ offsetY -= be.h;
+ }
+ if ("alignRight" in data.curr.attr && "alignLeft" in data.curr.attr) {
+ offsetX -= be.w / 2;
+ } else if ("toLeftOf" in data.curr.attr || "alignLeft" in data.curr.attr) {
+ offsetX -= be.w;
+ }
+
+ gc.setForeground(gc.registerColor(0x00FFFF00));
+
+ for (element in elements) {
+ drawElement(gc, element, offsetX, offsetY);
}
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AndroidConstants.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AndroidConstants.java
index d5d2185..73f6fcb 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AndroidConstants.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AndroidConstants.java
@@ -101,8 +101,6 @@ public class AndroidConstants {
public final static String FN_COMPILED_RESOURCE_CLASS = FN_RESOURCE_BASE + DOT_CLASS;
/** Manifest java class filename, i.e. "Manifest.java" */
public final static String FN_MANIFEST_CLASS = "Manifest.java"; //$NON-NLS-1$
- /** Dex conversion output filname, i.e. "classes.dex" */
- public final static String FN_CLASSES_DEX = "classes.dex"; //$NON-NLS-1$
/** Temporary packaged resources file name, i.e. "resources.ap_" */
public final static String FN_RESOURCES_AP_ = "resources.ap_"; //$NON-NLS-1$
/** Temporary packaged resources file name for a specific set of configuration */
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/MultiApkExportAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/MultiApkExportAction.java
index fe05b1d..aa4b700 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/MultiApkExportAction.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/MultiApkExportAction.java
@@ -17,7 +17,6 @@
package com.android.ide.eclipse.adt.internal.actions;
import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.adt.AndroidConstants;
import com.android.ide.eclipse.adt.internal.build.ApkBuilderHelper;
import com.android.ide.eclipse.adt.internal.project.ProjectHelper;
import com.android.ide.eclipse.adt.internal.project.ProjectState;
@@ -282,17 +281,23 @@ public class MultiApkExportAction implements IObjectActionDelegate {
apk.setOutputName(softVariant != null ? softVariant.getKey() : null, outputName);
// do the final export.
- IFile dexFile = projectBinFolder.getFile(AndroidConstants.FN_CLASSES_DEX);
+ IFile dexFile = projectBinFolder.getFile(SdkConstants.FN_APK_CLASSES_DEX);
String outputFile = binFolder.getFile(outputName).getLocation().toOSString();
// get the list of referenced projects.
IProject[] javaRefs = ProjectHelper.getReferencedProjects(project);
IJavaProject[] referencedJavaProjects = ApkBuilderHelper.getJavaProjects(javaRefs);
- helper.finalPackage(new File(projectBinFolderPath, pkgName).getAbsolutePath(),
+ helper.finalPackage(
+ new File(projectBinFolderPath, pkgName).getAbsolutePath(),
dexFile.getLocation().toOSString(),
- outputFile, javaProject, libProjects, referencedJavaProjects,
- apk.getAbi(), false /*debuggable*/);
+ outputFile,
+ false /*debugSign */,
+ javaProject,
+ libProjects,
+ referencedJavaProjects,
+ apk.getAbi(),
+ false /*debuggable*/);
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkBuilder.java
index 9cd3036..8360feb 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkBuilder.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkBuilder.java
@@ -350,7 +350,7 @@ public class ApkBuilder extends BaseBuilder {
// check classes.dex is present. If not we force to recreate it.
if (mConvertToDex == false) {
- tmp = outputFolder.findMember(AndroidConstants.FN_CLASSES_DEX);
+ tmp = outputFolder.findMember(SdkConstants.FN_APK_CLASSES_DEX);
if (tmp == null || tmp.exists() == false) {
mConvertToDex = true;
mBuildFinalPackage = true;
@@ -445,7 +445,7 @@ public class ApkBuilder extends BaseBuilder {
// then we check if we need to package the .class into classes.dex
if (mConvertToDex) {
if (helper.executeDx(javaProject, osBinPath, osBinPath + File.separator +
- AndroidConstants.FN_CLASSES_DEX, referencedJavaProjects) == false) {
+ SdkConstants.FN_APK_CLASSES_DEX, referencedJavaProjects) == false) {
// dx failed, we return
return allRefProjects;
}
@@ -477,10 +477,11 @@ public class ApkBuilder extends BaseBuilder {
// This is the default package with all the resources.
String classesDexPath = osBinPath + File.separator +
- AndroidConstants.FN_CLASSES_DEX;
+ SdkConstants.FN_APK_CLASSES_DEX;
if (helper.finalPackage(
osBinPath + File.separator + AndroidConstants.FN_RESOURCES_AP_,
- classesDexPath, osFinalPackagePath, javaProject, libProjects,
+ classesDexPath, osFinalPackagePath, true /*debugSign*/,
+ javaProject, libProjects,
referencedJavaProjects, null /*abiFilter*/, debuggable) == false) {
return allRefProjects;
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkBuilderHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkBuilderHelper.java
index 04acf44..3c2d86a 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkBuilderHelper.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkBuilderHelper.java
@@ -27,12 +27,14 @@ import com.android.ide.eclipse.adt.internal.sdk.Sdk;
import com.android.prefs.AndroidLocation.AndroidLocationException;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.SdkConstants;
+import com.android.sdklib.build.ApkBuilder;
+import com.android.sdklib.build.ApkBuilder.ApkCreationException;
+import com.android.sdklib.build.ApkBuilder.DuplicateFileException;
+import com.android.sdklib.build.ApkBuilder.JarStatus;
+import com.android.sdklib.build.ApkBuilder.SealedApkException;
import com.android.sdklib.internal.build.DebugKeyProvider;
-import com.android.sdklib.internal.build.JavaResourceFilter;
import com.android.sdklib.internal.build.SignedJarBuilder;
-import com.android.sdklib.internal.build.DebugKeyProvider.IKeyGenOutput;
import com.android.sdklib.internal.build.DebugKeyProvider.KeytoolException;
-import com.android.sdklib.internal.build.SignedJarBuilder.IZipEntryFilter;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
@@ -45,7 +47,6 @@ import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
@@ -54,73 +55,30 @@ import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jface.preference.IPreferenceStore;
import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
-import java.security.GeneralSecurityException;
-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
-import java.text.DateFormat;
import java.util.ArrayList;
-import java.util.Date;
import java.util.List;
+/**
+ * Helper with methods for the last 3 steps of the generation of an APK.
+ *
+ * {@link #packageResources(IFile, IProject[], String, int, String, String)} packages the
+ * application resources using aapt into a zip file that is ready to be integrated into the apk.
+ *
+ * {@link #executeDx(IJavaProject, String, String, IJavaProject[])} will convert the Java byte
+ * code into the Dalvik bytecode.
+ *
+ * {@link #finalPackage(String, String, String, boolean, IJavaProject, IProject[], IJavaProject[], String, boolean)}
+ * will make the apk from all the previous components.
+ *
+ */
public class ApkBuilderHelper {
- final static String GDBSERVER_NAME = "gdbserver"; //$NON-NLS-1$
-
private final IProject mProject;
private final PrintStream mOutStream;
private final PrintStream mErrStream;
- /**
- * Custom {@link IZipEntryFilter} to filter out everything that is not a standard java
- * resources, and also record whether the zip file contains native libraries.
- * <p/>Used in {@link SignedJarBuilder#writeZip(java.io.InputStream, IZipEntryFilter)} when
- * we only want the java resources from external jars.
- */
- private final static class JavaAndNativeResourceFilter extends JavaResourceFilter {
- private final List<String> mNativeLibs = new ArrayList<String>();
- private boolean mNativeLibInteference = false;
-
- @Override
- public boolean checkEntry(String name) {
- boolean value = super.checkEntry(name);
-
- // only do additional checks if the file passes the default checks.
- if (value) {
- if (name.endsWith(".so")) {
- mNativeLibs.add(name);
-
- // only .so located in lib/ will interfer with the installation
- if (name.startsWith("lib/")) {
- mNativeLibInteference = true;
- }
- } else if (name.endsWith(".jnilib")) {
- mNativeLibs.add(name);
- }
- }
-
- return value;
- }
-
- List<String> getNativeLibs() {
- return mNativeLibs;
- }
-
- boolean getNativeLibInterefence() {
- return mNativeLibInteference;
- }
-
- void clear() {
- mNativeLibs.clear();
- mNativeLibInteference = false;
- }
- }
-
- private final JavaAndNativeResourceFilter mResourceFilter = new JavaAndNativeResourceFilter();
-
public ApkBuilderHelper(IProject project, PrintStream outStream, PrintStream errStream) {
mProject = project;
mOutStream = outStream;
@@ -190,7 +148,6 @@ public class ApkBuilderHelper {
}
return true;
-
}
/**
@@ -199,6 +156,7 @@ public class ApkBuilderHelper {
* @param intermediateApk The path to the temporary resource file.
* @param dex The path to the dex file.
* @param output The path to the final package file to create.
+ * @param debugSign whether the apk must be signed with the debug key.
* @param javaProject the java project being compiled
* @param libProjects an optional list of library projects (can be null)
* @param referencedJavaProjects referenced projects.
@@ -209,128 +167,96 @@ public class ApkBuilderHelper {
* @return true if success, false otherwise.
*/
public boolean finalPackage(String intermediateApk, String dex, String output,
- final IJavaProject javaProject, IProject[] libProjects,
+ boolean debugSign, final IJavaProject javaProject, IProject[] libProjects,
IJavaProject[] referencedJavaProjects, String abiFilter, boolean debuggable) {
- FileOutputStream fos = null;
- try {
+ IProject project = javaProject.getProject();
+
+ String keystoreOsPath = null;
+ if (debugSign) {
IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore();
- String osKeyPath = store.getString(AdtPrefs.PREFS_CUSTOM_DEBUG_KEYSTORE);
- if (osKeyPath == null || new File(osKeyPath).exists() == false) {
- osKeyPath = DebugKeyProvider.getDefaultKeyStoreOsPath();
- AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, mProject,
- Messages.ApkBuilder_Using_Default_Key);
- } else {
- AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, mProject,
- String.format(Messages.ApkBuilder_Using_s_To_Sign, osKeyPath));
- }
+ keystoreOsPath = store.getString(AdtPrefs.PREFS_CUSTOM_DEBUG_KEYSTORE);
+ if (keystoreOsPath == null || new File(keystoreOsPath).isFile() == false) {
+ try {
+ keystoreOsPath = DebugKeyProvider.getDefaultKeyStoreOsPath();
+ AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, mProject,
+ Messages.ApkBuilder_Using_Default_Key);
+ } catch (KeytoolException e) {
+ String eMessage = e.getMessage();
+
+ // mark the project with the standard message
+ String msg = String.format(Messages.Final_Archive_Error_s, eMessage);
+ BaseProjectHelper.markResource(mProject, AndroidConstants.MARKER_PACKAGING, msg,
+ IMarker.SEVERITY_ERROR);
- // TODO: get the store type from somewhere else.
- DebugKeyProvider provider = new DebugKeyProvider(osKeyPath, null /* storeType */,
- new IKeyGenOutput() {
- public void err(String message) {
- AdtPlugin.printErrorToConsole(mProject,
- Messages.ApkBuilder_Signing_Key_Creation_s + message);
- }
+ // output more info in the console
+ AdtPlugin.printErrorToConsole(mProject,
+ msg,
+ String.format(Messages.ApkBuilder_JAVA_HOME_is_s, e.getJavaHome()),
+ Messages.ApkBuilder_Update_or_Execute_manually_s,
+ e.getCommandLine());
- public void out(String message) {
- AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE,
- mProject,
- Messages.ApkBuilder_Signing_Key_Creation_s + message);
- }
- });
- PrivateKey key = provider.getDebugKey();
- X509Certificate certificate = (X509Certificate)provider.getCertificate();
-
- if (key == null) {
- String msg = String.format(Messages.Final_Archive_Error_s,
- Messages.ApkBuilder_Unable_To_Gey_Key);
- AdtPlugin.printErrorToConsole(mProject, msg);
- BaseProjectHelper.markResource(mProject, AndroidConstants.MARKER_PACKAGING, msg,
- IMarker.SEVERITY_ERROR);
- return false;
- }
+ return false;
+ } catch (AndroidLocationException e) {
+ String eMessage = e.getMessage();
- // compare the certificate expiration date
- if (certificate != null && certificate.getNotAfter().compareTo(new Date()) < 0) {
- // TODO, regenerate a new one.
- String msg = String.format(Messages.Final_Archive_Error_s,
- String.format(Messages.ApkBuilder_Certificate_Expired_on_s,
- DateFormat.getInstance().format(certificate.getNotAfter())));
- AdtPlugin.printErrorToConsole(mProject, msg);
- BaseProjectHelper.markResource(mProject, AndroidConstants.MARKER_PACKAGING, msg,
- IMarker.SEVERITY_ERROR);
- return false;
- }
+ // mark the project with the standard message
+ String msg = String.format(Messages.Final_Archive_Error_s, eMessage);
+ BaseProjectHelper.markResource(mProject, AndroidConstants.MARKER_PACKAGING, msg,
+ IMarker.SEVERITY_ERROR);
- // create the jar builder.
- fos = new FileOutputStream(output);
- SignedJarBuilder builder = new SignedJarBuilder(fos, key, certificate);
-
- // add the intermediate file containing the compiled resources.
- AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, mProject,
- String.format(Messages.ApkBuilder_Packaging_s, intermediateApk));
- FileInputStream fis = new FileInputStream(intermediateApk);
- try {
- builder.writeZip(fis, null /* filter */);
- } finally {
- fis.close();
+ return false;
+ }
+ } else {
+ AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, mProject,
+ String.format(Messages.ApkBuilder_Using_s_To_Sign, keystoreOsPath));
}
+ }
- // Now we add the new file to the zip archive for the classes.dex file.
- AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, mProject,
- String.format(Messages.ApkBuilder_Packaging_s,
- AndroidConstants.FN_CLASSES_DEX));
- File entryFile = new File(dex);
- builder.writeFile(entryFile, AndroidConstants.FN_CLASSES_DEX);
+
+ try {
+ ApkBuilder apkBuilder = new ApkBuilder(output, intermediateApk, dex, keystoreOsPath,
+ AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE ?
+ AdtPlugin.getOutPrintStream(project, null): null);
+ apkBuilder.setDebugMode(debuggable);
// Now we write the standard resources from the project and the referenced projects.
- writeStandardResources(builder, javaProject, referencedJavaProjects);
+ writeStandardResources(apkBuilder, javaProject, referencedJavaProjects);
- // Now we write the standard resources from the external libraries
+ // Now we write the standard resources from the external jars
for (String libraryOsPath : getExternalJars()) {
- AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, mProject,
- String.format(Messages.ApkBuilder_Packaging_s, libraryOsPath));
- try {
- fis = new FileInputStream(libraryOsPath);
- mResourceFilter.clear();
- builder.writeZip(fis, mResourceFilter);
-
- // check if we found native libraries in the external library. This
- // constitutes an error or warning depending on if they are in lib/
- List<String> nativeLibs = mResourceFilter.getNativeLibs();
- boolean nativeInterference = mResourceFilter.getNativeLibInterefence();
- if (nativeLibs.size() > 0) {
- String libName = new File(libraryOsPath).getName();
- String msg = String.format("Native libraries detected in '%1$s'. See console for more information.",
- libName);
-
-
- BaseProjectHelper.markResource(mProject, AndroidConstants.MARKER_PACKAGING,
- msg,
- nativeInterference ||
- AdtPrefs.getPrefs().getBuildForceErrorOnNativeLibInJar() ?
- IMarker.SEVERITY_ERROR : IMarker.SEVERITY_WARNING);
-
- ArrayList<String> consoleMsgs = new ArrayList<String>();
- consoleMsgs.add(String.format(
- "The library '%1$s' contains native libraries that will not run on the device.",
- libName));
- if (nativeInterference) {
- consoleMsgs.add("Additionally some of those libraries will interfer with the installation of the application because of their location in lib/");
- consoleMsgs.add("lib/ is reserved for NDK libraries.");
- }
- consoleMsgs.add("The following libraries were found:");
- for (String lib : nativeLibs) {
- consoleMsgs.add(" - " + lib);
- }
- AdtPlugin.printErrorToConsole(mProject,
- consoleMsgs.toArray());
+ JarStatus status = apkBuilder.addResourcesFromJar(new File(libraryOsPath));
+
+ // check if we found native libraries in the external library. This
+ // constitutes an error or warning depending on if they are in lib/
+ if (status.getNativeLibs().size() > 0) {
+ String libName = new File(libraryOsPath).getName();
+ String msg = String.format(
+ "Native libraries detected in '%1$s'. See console for more information.",
+ libName);
- return false;
+ BaseProjectHelper.markResource(mProject, AndroidConstants.MARKER_PACKAGING,
+ msg,
+ status.hasNativeLibsConflicts() ||
+ AdtPrefs.getPrefs().getBuildForceErrorOnNativeLibInJar() ?
+ IMarker.SEVERITY_ERROR : IMarker.SEVERITY_WARNING);
+
+ ArrayList<String> consoleMsgs = new ArrayList<String>();
+ consoleMsgs.add(String.format(
+ "The library '%1$s' contains native libraries that will not run on the device.",
+ libName));
+ if (status.hasNativeLibsConflicts()) {
+ consoleMsgs.add("Additionally some of those libraries will interfer with the installation of the application because of their location in lib/");
+ consoleMsgs.add("lib/ is reserved for NDK libraries.");
+ }
+ consoleMsgs.add("The following libraries were found:");
+ for (String lib : status.getNativeLibs()) {
+ consoleMsgs.add(" - " + lib);
}
- } finally {
- fis.close();
+ AdtPlugin.printErrorToConsole(mProject,
+ consoleMsgs.toArray());
+
+ return false;
}
}
@@ -339,8 +265,8 @@ public class ApkBuilderHelper {
IResource libFolder = mProject.findMember(SdkConstants.FD_NATIVE_LIBS);
if (libFolder != null && libFolder.exists() &&
libFolder.getType() == IResource.FOLDER) {
- // look inside and put .so in lib/* by keeping the relative folder path.
- writeNativeLibraries((IFolder) libFolder, builder, abiFilter, debuggable);
+ // get a File for the folder.
+ apkBuilder.addNativeLibraries(libFolder.getLocation().toFile(), abiFilter);
}
// write the native libraries for the library projects.
@@ -349,59 +275,36 @@ public class ApkBuilderHelper {
libFolder = lib.findMember(SdkConstants.FD_NATIVE_LIBS);
if (libFolder != null && libFolder.exists() &&
libFolder.getType() == IResource.FOLDER) {
- // look inside and put .so in lib/* by keeping the relative folder path.
- writeNativeLibraries((IFolder) libFolder, builder, abiFilter, debuggable);
+ apkBuilder.addNativeLibraries(libFolder.getLocation().toFile(), abiFilter);
}
}
}
- // close the jar file and write the manifest and sign it.
- builder.close();
- } catch (GeneralSecurityException e1) {
- // mark project and return
- String msg = String.format(Messages.Final_Archive_Error_s, e1.getMessage());
- AdtPlugin.printErrorToConsole(mProject, msg);
- BaseProjectHelper.markResource(mProject, AndroidConstants.MARKER_PACKAGING, msg,
- IMarker.SEVERITY_ERROR);
- return false;
- } catch (IOException e1) {
+ // seal the APK.
+ apkBuilder.sealApk();
+ return true;
+ } catch (CoreException e) {
// mark project and return
- String msg = String.format(Messages.Final_Archive_Error_s, e1.getMessage());
+ String msg = String.format(Messages.Final_Archive_Error_s, e.getMessage());
AdtPlugin.printErrorToConsole(mProject, msg);
BaseProjectHelper.markResource(mProject, AndroidConstants.MARKER_PACKAGING, msg,
IMarker.SEVERITY_ERROR);
- return false;
- } catch (KeytoolException e) {
- String eMessage = e.getMessage();
-
- // mark the project with the standard message
- String msg = String.format(Messages.Final_Archive_Error_s, eMessage);
- BaseProjectHelper.markResource(mProject, AndroidConstants.MARKER_PACKAGING, msg,
- IMarker.SEVERITY_ERROR);
-
- // output more info in the console
- AdtPlugin.printErrorToConsole(mProject,
- msg,
- String.format(Messages.ApkBuilder_JAVA_HOME_is_s, e.getJavaHome()),
- Messages.ApkBuilder_Update_or_Execute_manually_s,
- e.getCommandLine());
- } catch (AndroidLocationException e) {
- String eMessage = e.getMessage();
-
- // mark the project with the standard message
- String msg = String.format(Messages.Final_Archive_Error_s, eMessage);
- BaseProjectHelper.markResource(mProject, AndroidConstants.MARKER_PACKAGING, msg,
- IMarker.SEVERITY_ERROR);
-
- // and also output it in the console
- AdtPlugin.printErrorToConsole(mProject, msg);
- } catch (CoreException e) {
+ } catch (ApkCreationException e) {
// mark project and return
String msg = String.format(Messages.Final_Archive_Error_s, e.getMessage());
AdtPlugin.printErrorToConsole(mProject, msg);
BaseProjectHelper.markResource(mProject, AndroidConstants.MARKER_PACKAGING, msg,
IMarker.SEVERITY_ERROR);
- return false;
+ } catch (DuplicateFileException e) {
+ String msg1 = String.format(
+ "Found duplicate file for APK: %1$s\nOrigin 1: %2$s\nOrigin 2: %3$s",
+ e.getArchivePath(), e.getFile1(), e.getFile2());
+ String msg2 = String.format(Messages.Final_Archive_Error_s, msg1);
+ AdtPlugin.printErrorToConsole(mProject, msg2);
+ BaseProjectHelper.markResource(mProject, AndroidConstants.MARKER_PACKAGING, msg2,
+ IMarker.SEVERITY_ERROR);
+ } catch (SealedApkException e) {
+ // this won't happen as we control when the apk is sealed.
} catch (Exception e) {
// try to catch other exception to actually display an error. This will be useful
// if we get an NPE or something so that we can at least notify the user that something
@@ -416,18 +319,9 @@ public class ApkBuilderHelper {
AdtPlugin.printErrorToConsole(mProject, msg);
BaseProjectHelper.markResource(mProject, AndroidConstants.MARKER_PACKAGING, msg,
IMarker.SEVERITY_ERROR);
- return false;
- } finally {
- if (fos != null) {
- try {
- fos.close();
- } catch (IOException e) {
- // pass.
- }
- }
}
- return true;
+ return false;
}
/**
@@ -639,80 +533,29 @@ public class ApkBuilderHelper {
/**
- * Writes native libraries into a {@link SignedJarBuilder}.
- * <p/>The native libraries must be located in a given main folder. Under this folder, it is
- * expected that the libraries are under a sub-folder that represents the ABI of the library.
- *
- * The path in the archive is based on the ABI folder name, and located under a main
- * folder called "lib".
- *
- * This method also packages any "gdbserver" executable it finds in the ABI folders, if
- * <var>debuggable</var> is set to true.
- *
- * @param rootFolder The folder containing the native libraries.
- * @param jarBuilder the {@link SignedJarBuilder} used to create the archive.
- * @param abiFilter an optional filter. If not null, then only the matching ABI is included in
- * the final archive
- * @param debuggable whether the application is debuggable. If <code>true</code> then gdbserver
- * executables will be packaged as well.
- * @throws CoreException
- * @throws IOException
- */
- private void writeNativeLibraries(IFolder rootFolder, SignedJarBuilder jarBuilder,
- String abiFilter, boolean debuggable) throws CoreException, IOException {
- // the native files must be under a single sub-folder under the main root folder.
- // the sub-folder represents the abi for the native libs
- IResource[] abis = rootFolder.members();
- for (IResource abi : abis) {
- if (abi.getType() == IResource.FOLDER) { // ignore non folders.
-
- // check the abi filter and reject all other ABIs
- if (abiFilter != null && abiFilter.equals(abi.getName()) == false) {
- continue;
- }
-
- IResource[] libs = ((IFolder)abi).members();
-
- for (IResource lib : libs) {
- if (lib.getType() == IResource.FILE) { // ignore non files.
- IPath path = lib.getFullPath();
-
- // check the extension.
- String ext = path.getFileExtension();
- if (AndroidConstants.EXT_NATIVE_LIB.equalsIgnoreCase(ext) ||
- (debuggable && GDBSERVER_NAME.equals(lib.getName()))) {
- // compute the path inside the archive.
- IPath apkPath = new Path(SdkConstants.FD_APK_NATIVE_LIBS);
- apkPath = apkPath.append(abi.getName()).append(lib.getName());
-
- // writes the file in the apk.
- jarBuilder.writeFile(lib.getLocation().toFile(), apkPath.toString());
- }
- }
- }
- }
- }
- }
-
- /**
* Writes the standard resources of a project and its referenced projects
* into a {@link SignedJarBuilder}.
* Standard resources are non java/aidl files placed in the java package folders.
- * @param jarBuilder the {@link SignedJarBuilder}.
+ * @param apkBuilder the {@link ApkBuilder}.
* @param javaProject the javaProject object.
* @param referencedJavaProjects the java projects that this project references.
- * @throws IOException
+ * @throws ApkCreationException if an error occurred
+ * @throws SealedApkException if the APK is already sealed.
+ * @throws DuplicateFileException if a file conflicts with another already added to the APK
+ * at the same location inside the APK archive.
* @throws CoreException
*/
- private void writeStandardResources(SignedJarBuilder jarBuilder, IJavaProject javaProject,
- IJavaProject[] referencedJavaProjects) throws IOException, CoreException {
+ private void writeStandardResources(ApkBuilder apkBuilder, IJavaProject javaProject,
+ IJavaProject[] referencedJavaProjects)
+ throws DuplicateFileException, ApkCreationException, SealedApkException,
+ CoreException {
IWorkspace ws = ResourcesPlugin.getWorkspace();
IWorkspaceRoot wsRoot = ws.getRoot();
// create a list of path already put into the archive, in order to detect conflict
ArrayList<String> list = new ArrayList<String>();
- writeStandardProjectResources(jarBuilder, javaProject, wsRoot, list);
+ writeStandardProjectResources(apkBuilder, javaProject, wsRoot, list);
for (IJavaProject referencedJavaProject : referencedJavaProjects) {
// only include output from non android referenced project
@@ -720,7 +563,7 @@ public class ApkBuilderHelper {
// instrumentation projects that need to reference the projects to be tested).
if (referencedJavaProject.getProject().hasNature(
AndroidConstants.NATURE_DEFAULT) == false) {
- writeStandardProjectResources(jarBuilder, referencedJavaProject, wsRoot, list);
+ writeStandardProjectResources(apkBuilder, referencedJavaProject, wsRoot, list);
}
}
}
@@ -728,15 +571,18 @@ public class ApkBuilderHelper {
/**
* Writes the standard resources of a {@link IJavaProject} into a {@link SignedJarBuilder}.
* Standard resources are non java/aidl files placed in the java package folders.
- * @param jarBuilder the {@link SignedJarBuilder}.
+ * @param jarBuilder the {@link ApkBuilder}.
* @param javaProject the javaProject object.
* @param wsRoot the {@link IWorkspaceRoot}.
* @param list a list of files already added to the archive, to detect conflicts.
- * @throws IOException
+ * @throws ApkCreationException if an error occurred
+ * @throws SealedApkException if the APK is already sealed.
+ * @throws DuplicateFileException if a file conflicts with another already added to the APK
+ * at the same location inside the APK archive.
*/
- private void writeStandardProjectResources(SignedJarBuilder jarBuilder,
+ private void writeStandardProjectResources(ApkBuilder apkBuilder,
IJavaProject javaProject, IWorkspaceRoot wsRoot, ArrayList<String> list)
- throws IOException {
+ throws DuplicateFileException, ApkCreationException, SealedApkException {
// get the source pathes
ArrayList<IPath> sourceFolders = BaseProjectHelper.getSourceClasspaths(javaProject);
@@ -744,74 +590,12 @@ public class ApkBuilderHelper {
for (IPath sourcePath : sourceFolders) {
IResource sourceResource = wsRoot.findMember(sourcePath);
if (sourceResource != null && sourceResource.getType() == IResource.FOLDER) {
- writeStandardSourceFolderResources(jarBuilder, sourcePath, (IFolder)sourceResource,
- list);
- }
- }
- }
-
- /**
- * Recursively writes the standard resources of a source folder into a {@link SignedJarBuilder}.
- * Standard resources are non java/aidl files placed in the java package folders.
- * @param jarBuilder the {@link SignedJarBuilder}.
- * @param sourceFolder the {@link IPath} of the source folder.
- * @param currentFolder The current folder we're recursively processing.
- * @param list a list of files already added to the archive, to detect conflicts.
- * @throws IOException
- */
- private void writeStandardSourceFolderResources(SignedJarBuilder jarBuilder, IPath sourceFolder,
- IFolder currentFolder, ArrayList<String> list) throws IOException {
- try {
- IResource[] members = currentFolder.members();
-
- for (IResource member : members) {
- int type = member.getType();
- if (type == IResource.FILE && member.exists()) {
- if (checkFileForPackaging((IFile)member)) {
- // this files must be added to the archive.
- IPath fullPath = member.getFullPath();
-
- // We need to create its path inside the archive.
- // This path is relative to the source folder.
- IPath relativePath = fullPath.removeFirstSegments(
- sourceFolder.segmentCount());
- String zipPath = relativePath.toString();
-
- // lets check it's not already in the list of path added to the archive
- if (list.indexOf(zipPath) != -1) {
- AdtPlugin.printErrorToConsole(mProject,
- String.format(
- Messages.ApkBuilder_s_Conflict_with_file_s,
- fullPath, zipPath));
- } else {
- // get the File object
- File entryFile = member.getLocation().toFile();
-
- AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, mProject,
- String.format(
- Messages.ApkBuilder_Packaging_s_into_s,
- fullPath, zipPath));
-
- // write it in the zip archive
- jarBuilder.writeFile(entryFile, zipPath);
-
- // and add it to the list of entries
- list.add(zipPath);
- }
- }
- } else if (type == IResource.FOLDER) {
- if (checkFolderForPackaging((IFolder)member)) {
- writeStandardSourceFolderResources(jarBuilder, sourceFolder,
- (IFolder)member, list);
- }
- }
+ // get a File from the IResource
+ apkBuilder.addSourceFolder(sourceResource.getLocation().toFile());
}
- } catch (CoreException e) {
- // if we can't get the members of the folder, we just don't do anything.
}
}
-
/**
* Returns an array of external jar files used by the project.
* @return an array of OS-specific absolute file paths
@@ -838,15 +622,11 @@ public class ApkBuilderHelper {
// check the name ends with .jar
if (AndroidConstants.EXT_JAR.equalsIgnoreCase(path.getFileExtension())) {
- boolean local = false;
IResource resource = wsRoot.findMember(path);
if (resource != null && resource.exists() &&
resource.getType() == IResource.FILE) {
- local = true;
oslibraryList.add(resource.getLocation().toOSString());
- }
-
- if (local == false) {
+ } else {
// if the jar path doesn't match a workspace resource,
// then we get an OSString and check if this links to a valid file.
String osFullPath = path.toOSString();
@@ -922,7 +702,7 @@ public class ApkBuilderHelper {
String name = file.getName();
String ext = file.getFileExtension();
- return JavaResourceFilter.checkFileForPackaging(name, ext);
+ return ApkBuilder.checkFileForPackaging(name, ext);
}
/**
@@ -932,7 +712,7 @@ public class ApkBuilderHelper {
*/
static boolean checkFolderForPackaging(IFolder folder) {
String name = folder.getName();
- return JavaResourceFilter.checkFolderForPackaging(name);
+ return ApkBuilder.checkFolderForPackaging(name);
}
/**
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkDeltaVisitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkDeltaVisitor.java
index 643fee5..81f06c1 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkDeltaVisitor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkDeltaVisitor.java
@@ -193,7 +193,7 @@ public class ApkDeltaVisitor extends BaseDeltaVisitor
if (mOutputPath.equals(parentPath)) {
String resourceName = resource.getName();
// check if classes.dex was removed
- if (resourceName.equalsIgnoreCase(AndroidConstants.FN_CLASSES_DEX)) {
+ if (resourceName.equalsIgnoreCase(SdkConstants.FN_APK_CLASSES_DEX)) {
mConvertToDex = true;
mMakeFinalPackage = true;
} else if (resourceName.equalsIgnoreCase(
@@ -237,7 +237,7 @@ public class ApkDeltaVisitor extends BaseDeltaVisitor
// inside the native library folder. Test if the changed resource is a .so file.
if (type == IResource.FILE &&
(AndroidConstants.EXT_NATIVE_LIB.equalsIgnoreCase(path.getFileExtension())
- || ApkBuilderHelper.GDBSERVER_NAME.equals(resource.getName()))) {
+ || SdkConstants.FN_GDBSERVER.equals(resource.getName()))) {
mMakeFinalPackage = true;
return false; // return false for file.
}