diff options
Diffstat (limited to 'eclipse')
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. } |