diff options
Diffstat (limited to 'eclipse')
6 files changed, 269 insertions, 374 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java index e915544..e8fbadb 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java @@ -21,8 +21,6 @@ import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.AndroidPrintStream; import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity; -import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; -import com.android.ide.eclipse.adt.internal.project.ProjectHelper; import com.android.ide.eclipse.adt.internal.sdk.Sdk; import com.android.prefs.AndroidLocation.AndroidLocationException; import com.android.sdklib.IAndroidTarget; @@ -33,11 +31,9 @@ import com.android.sdklib.build.ApkBuilder.JarStatus; import com.android.sdklib.build.ApkBuilder.SigningInfo; import com.android.sdklib.build.ApkCreationException; import com.android.sdklib.build.DuplicateFileException; -import com.android.sdklib.build.IArchiveBuilder; import com.android.sdklib.build.SealedApkException; import com.android.sdklib.internal.build.DebugKeyProvider; import com.android.sdklib.internal.build.DebugKeyProvider.KeytoolException; -import com.android.sdklib.internal.build.SignedJarBuilder; import com.android.sdklib.util.GrabProcessOutput; import com.android.sdklib.util.GrabProcessOutput.IProcessOutput; import com.android.sdklib.util.GrabProcessOutput.Wait; @@ -46,9 +42,6 @@ import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IResourceProxy; -import org.eclipse.core.resources.IResourceProxyVisitor; -import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; @@ -69,8 +62,12 @@ import java.io.PrintStream; import java.security.PrivateKey; import java.security.cert.X509Certificate; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.TreeMap; /** @@ -108,11 +105,14 @@ public class BuildHelper { private final boolean mVerbose; private final boolean mDebugMode; + private final Set<String> mCompiledCodePaths = new HashSet<String>(); + public static final boolean BENCHMARK_FLAG = false; public static long sStartOverallTime = 0; public static long sStartJavaCTime = 0; private final static int MILLION = 1000000; + private String mProguardFile; /** * An object able to put a marker on a resource. @@ -128,14 +128,18 @@ public class BuildHelper { * @param errStream * @param debugMode whether this is a debug build * @param verbose + * @throws CoreException */ public BuildHelper(IProject project, AndroidPrintStream outStream, - AndroidPrintStream errStream, boolean debugMode, boolean verbose) { + AndroidPrintStream errStream, boolean debugMode, boolean verbose, + ResourceMarker resMarker) throws CoreException { mProject = project; mOutStream = outStream; mErrStream = errStream; mDebugMode = debugMode; mVerbose = verbose; + + gatherPaths(resMarker); } public void updateCrunchCache() throws AaptExecException, AaptResultException { @@ -169,11 +173,6 @@ public class BuildHelper { } } - public static void writeResources(IArchiveBuilder builder, IJavaProject javaProject) - throws DuplicateFileException, ApkCreationException, SealedApkException, CoreException { - writeStandardResources(builder, javaProject, null); - } - /** * Packages the resources of the projet into a .ap_ file. * @param manifestFile the manifest of the project. @@ -287,9 +286,7 @@ public class BuildHelper { * @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 javaProject the java project being compiled * @param libProjects an optional list of library projects (can be null) - * @param referencedJavaProjects referenced projects. * @return true if success, false otherwise. * @throws ApkCreationException * @throws AndroidLocationException @@ -299,8 +296,7 @@ public class BuildHelper { * @throws DuplicateFileException */ public void finalDebugPackage(String intermediateApk, String dex, String output, - final IJavaProject javaProject, List<IProject> libProjects, - List<IJavaProject> referencedJavaProjects, ResourceMarker resMarker) + List<IProject> libProjects, ResourceMarker resMarker) throws ApkCreationException, KeytoolException, AndroidLocationException, NativeLibInJarException, DuplicateFileException, CoreException { @@ -324,8 +320,7 @@ public class BuildHelper { // from the keystore, get the signing info SigningInfo info = ApkBuilder.getDebugKey(keystoreOsPath, mVerbose ? mOutStream : null); - finalPackage(intermediateApk, dex, output, javaProject, libProjects, - referencedJavaProjects, + finalPackage(intermediateApk, dex, output, libProjects, info != null ? info.key : null, info != null ? info.certificate : null, resMarker); } @@ -341,9 +336,7 @@ public class BuildHelper { * @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. * @param abiFilter an optional filter. If not null, then only the matching ABI is included in * the final archive * @return true if success, false otherwise. @@ -353,9 +346,8 @@ public class BuildHelper { * @throws DuplicateFileException */ public void finalPackage(String intermediateApk, String dex, String output, - final IJavaProject javaProject, List<IProject> libProjects, - List<IJavaProject> referencedJavaProjects, PrivateKey key, - X509Certificate certificate, ResourceMarker resMarker) + List<IProject> libProjects, + PrivateKey key, X509Certificate certificate, ResourceMarker resMarker) throws NativeLibInJarException, ApkCreationException, DuplicateFileException, CoreException { @@ -365,19 +357,24 @@ public class BuildHelper { mVerbose ? mOutStream: null); apkBuilder.setDebugMode(mDebugMode); - // Now we write the standard resources from the project and the referenced projects. - writeStandardResources(apkBuilder, javaProject, referencedJavaProjects); + // either use the full compiled code paths or just the proguard file + // if present + Collection<String> pathsCollection = mCompiledCodePaths; + if (mProguardFile != null) { + pathsCollection = Collections.singletonList(mProguardFile); + mProguardFile = null; + } - // Now we write the standard resources from the external jars - for (String libraryOsPath : getExternalDependencies(resMarker)) { - File libFile = new File(libraryOsPath); - if (libFile.isFile()) { - JarStatus jarStatus = apkBuilder.addResourcesFromJar(new File(libraryOsPath)); + // Now we write the standard resources from all the output paths. + for (String path : pathsCollection) { + File file = new File(path); + if (file.isFile()) { + JarStatus jarStatus = apkBuilder.addResourcesFromJar(file); // check if we found native libraries in the external library. This // constitutes an error or warning depending on if they are in lib/ if (jarStatus.getNativeLibs().size() > 0) { - String libName = new File(libraryOsPath).getName(); + String libName = file.getName(); String msg = String.format( "Native libraries detected in '%1$s'. See console for more information.", @@ -418,11 +415,11 @@ public class BuildHelper { } } } - } else if (libFile.isDirectory()) { + } else if (file.isDirectory()) { // this is technically not a source folder (class folder instead) but since we // only care about Java resources (ie non class/java files) this will do the // same - apkBuilder.addSourceFolder(libFile); + apkBuilder.addSourceFolder(file); } } @@ -453,66 +450,15 @@ public class BuildHelper { } } - /** - * Return a list of the project output for compiled Java code. - * @return - * @throws CoreException - */ - public String[] getProjectJavaOutputs() throws CoreException { - IFolder outputFolder = BaseProjectHelper.getJavaOutputFolder(mProject); - - // get the list of referenced projects output to add - List<IProject> javaProjects = ProjectHelper.getReferencedProjects(mProject); - List<IJavaProject> referencedJavaProjects = BuildHelper.getJavaProjects(javaProjects); - - // get the project output, and since it's a new list object, just add the outputFolder - // of the project directly to it. - List<String> projectOutputs = getProjectJavaOutputs(referencedJavaProjects); - - projectOutputs.add(0, outputFolder.getLocation().toOSString()); - - return projectOutputs.toArray(new String[projectOutputs.size()]); + public void setProguardOutput(String proguardFile) { + mProguardFile = proguardFile; } - /** - * Returns an array for all the compiled code for the project. This can include the - * code compiled by Eclipse for the main project and dependencies (Java only projects), as well - * as external jars used by the project or its library. - * - * This array of paths is compatible with the input for dx and can be passed as is to - * {@link #executeDx(IJavaProject, String[], String)}. - * - * @param resMarker - * @return a array (never empty) containing paths to compiled code. - * @throws CoreException - */ - public String[] getCompiledCodePaths(boolean includeProjectOutputs, ResourceMarker resMarker) - throws CoreException { - - // get the list of libraries to include with the source code - String[] libraries = getExternalDependencies(resMarker); - - int startIndex = 0; - - String[] compiledPaths; - - if (includeProjectOutputs) { - String[] projectOutputs = getProjectJavaOutputs(); - - compiledPaths = new String[libraries.length + projectOutputs.length]; - - System.arraycopy(projectOutputs, 0, compiledPaths, 0, projectOutputs.length); - startIndex = projectOutputs.length; - } else { - compiledPaths = new String[libraries.length]; - } - - System.arraycopy(libraries, 0, compiledPaths, startIndex, libraries.length); - - return compiledPaths; + public Collection<String> getCompiledCodePaths() { + return mCompiledCodePaths; } - public void runProguard(List<File> proguardConfigs, File inputJar, String[] jarFiles, + public void runProguard(List<File> proguardConfigs, File inputJar, Collection<String> jarFiles, File obfuscatedJar, File logOutput) throws ProguardResultException, ProguardExecException, IOException { IAndroidTarget target = Sdk.getCurrent().getTarget(mProject); @@ -723,13 +669,14 @@ public class BuildHelper { /** * Execute the Dx tool for dalvik code conversion. * @param javaProject The java project - * @param inputPath the path to the main input of dex + * @param inputPaths the input paths for DX * @param osOutFilePath the path of the dex file to create. * * @throws CoreException * @throws DexException */ - public void executeDx(IJavaProject javaProject, String[] inputPaths, String osOutFilePath) + public void executeDx(IJavaProject javaProject, Collection<String> inputPaths, + String osOutFilePath) throws CoreException, DexException { // get the dex wrapper @@ -917,153 +864,94 @@ public class BuildHelper { } /** - * 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 builder the archive builder. - * @param javaProject the javaProject object. - * @param referencedJavaProjects the java projects that this project references. - * @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 static void writeStandardResources(IArchiveBuilder builder, IJavaProject javaProject, - List<IJavaProject> referencedJavaProjects) - throws DuplicateFileException, ApkCreationException, SealedApkException, - CoreException { - IWorkspace ws = ResourcesPlugin.getWorkspace(); - IWorkspaceRoot wsRoot = ws.getRoot(); - - writeStandardProjectResources(builder, javaProject, wsRoot); - - if (referencedJavaProjects != null) { - for (IJavaProject referencedJavaProject : referencedJavaProjects) { - // only include output from non android referenced project - // (This is to handle the case of reference Android projects in the context of - // instrumentation projects that need to reference the projects to be tested). - if (referencedJavaProject.getProject().hasNature( - AdtConstants.NATURE_DEFAULT) == false) { - writeStandardProjectResources(builder, referencedJavaProject, wsRoot); - } - } - } - } - - /** - * 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 ApkBuilder}. - * @param javaProject the javaProject object. - * @param wsRoot the {@link IWorkspaceRoot}. - * @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. + * Computes all the project output and dependencies that must go into building the apk. + * + * @param resMarker * @throws CoreException */ - private static void writeStandardProjectResources(IArchiveBuilder builder, - IJavaProject javaProject, IWorkspaceRoot wsRoot) - throws DuplicateFileException, ApkCreationException, SealedApkException, CoreException { - // get the source pathes - List<IPath> sourceFolders = BaseProjectHelper.getSourceClasspaths(javaProject); - - // loop on them and then recursively go through the content looking for matching files. - for (IPath sourcePath : sourceFolders) { - IResource sourceResource = wsRoot.findMember(sourcePath); - if (sourceResource != null && sourceResource.getType() == IResource.FOLDER) { - writeFolderResources(builder, javaProject, (IFolder) sourceResource); - } - } - } - - private static void writeFolderResources(IArchiveBuilder builder, - final IJavaProject javaProject, IFolder root) throws CoreException, - ApkCreationException, SealedApkException, DuplicateFileException { - final List<IPath> pathsToPackage = new ArrayList<IPath>(); - root.accept(new IResourceProxyVisitor() { - @Override - public boolean visit(IResourceProxy proxy) throws CoreException { - if (proxy.getType() == IResource.FOLDER) { - // If this folder isn't wanted, don't traverse into it. - return ApkBuilder.checkFolderForPackaging(proxy.getName()); - } - // If it's not a folder, it must be a file. We won't see any other resource type. - if (!ApkBuilder.checkFileForPackaging(proxy.getName())) { - return true; - } - IResource res = proxy.requestResource(); - if (!javaProject.isOnClasspath(res)) { - return true; - } - // Just record that we need to package this. Packaging here throws - // inappropriate checked exceptions. - IPath location = res.getLocation(); - pathsToPackage.add(location); - return true; - } - }, 0); - IPath rootLocation = root.getLocation(); - for (IPath path : pathsToPackage) { - IPath archivePath = path.makeRelativeTo(rootLocation); - builder.addFile(path.toFile(), archivePath.toString()); - } - } + private void gatherPaths(ResourceMarker resMarker) + throws CoreException { + IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot(); - /** - * Returns an array of external dependencies used the project. This can be paths to jar files - * or to source folders. - * - * @param resMarker if non null, used to put Resource marker on problem files. - * @return an array of OS-specific absolute file paths - */ - private final String[] getExternalDependencies(ResourceMarker resMarker) { - // get a java project from it + // get a java project for the project. IJavaProject javaProject = JavaCore.create(mProject); - IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot(); - ArrayList<String> oslibraryList = new ArrayList<String>(); + // get the output of the main project + IPath path = javaProject.getOutputLocation(); + IResource outputResource = wsRoot.findMember(path); + if (outputResource != null && outputResource.getType() == IResource.FOLDER) { + mCompiledCodePaths.add(outputResource.getLocation().toOSString()); + } // we could use IJavaProject.getResolvedClasspath directly, but we actually // want to see the containers themselves. IClasspathEntry[] classpaths = javaProject.readRawClasspath(); if (classpaths != null) { for (IClasspathEntry e : classpaths) { - // if this is a classpath variable reference, we resolve it. - if (e.getEntryKind() == IClasspathEntry.CPE_VARIABLE) { - e = JavaCore.getResolvedClasspathEntry(e); + // ignore non exported entries, unless it's the LIBRARIES container, + // in which case we always want it (there may be some older projects that + // have it as non exported). + if (e.isExported() || + (e.getEntryKind() == IClasspathEntry.CPE_CONTAINER && + e.getPath().toString().equals(AdtConstants.CONTAINER_LIBRARIES))) { + handleCPE(e, javaProject, wsRoot, resMarker); } + } + } + } - if (e.getEntryKind() == IClasspathEntry.CPE_LIBRARY) { - handleClasspathEntry(e, wsRoot, oslibraryList, resMarker); - } else if (e.getEntryKind() == IClasspathEntry.CPE_CONTAINER) { - // get the container - try { - IClasspathContainer container = JavaCore.getClasspathContainer( - e.getPath(), javaProject); - // ignore the system and default_system types as they represent - // libraries that are part of the runtime. - if (container.getKind() == IClasspathContainer.K_APPLICATION) { - IClasspathEntry[] entries = container.getClasspathEntries(); - for (IClasspathEntry entry : entries) { - handleClasspathEntry(entry, wsRoot, oslibraryList, resMarker); - } - } - } catch (JavaModelException jme) { - // can't resolve the container? ignore it. - AdtPlugin.log(jme, "Failed to resolve ClasspathContainer: %s", e.getPath()); + private void handleCPE(IClasspathEntry entry, IJavaProject javaProject, + IWorkspaceRoot wsRoot, ResourceMarker resMarker) { + + // if this is a classpath variable reference, we resolve it. + if (entry.getEntryKind() == IClasspathEntry.CPE_VARIABLE) { + entry = JavaCore.getResolvedClasspathEntry(entry); + } + + if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) { + IProject refProject = wsRoot.getProject(entry.getPath().lastSegment()); + try { + // ignore if it's an Android project, or if it's not a Java Project + if (refProject.hasNature(JavaCore.NATURE_ID) && + refProject.hasNature(AdtConstants.NATURE_DEFAULT) == false) { + IJavaProject refJavaProject = JavaCore.create(refProject); + + // get the output folder + IPath path = refJavaProject.getOutputLocation(); + IResource outputResource = wsRoot.findMember(path); + if (outputResource != null && outputResource.getType() == IResource.FOLDER) { + mCompiledCodePaths.add(outputResource.getLocation().toOSString()); } } + } catch (CoreException exception) { + // can't query the project nature? ignore } - } - return oslibraryList.toArray(new String[oslibraryList.size()]); + } else if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) { + handleClasspathLibrary(entry, wsRoot, resMarker); + } else if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) { + // get the container + try { + IClasspathContainer container = JavaCore.getClasspathContainer( + entry.getPath(), javaProject); + // ignore the system and default_system types as they represent + // libraries that are part of the runtime. + if (container.getKind() == IClasspathContainer.K_APPLICATION) { + IClasspathEntry[] entries = container.getClasspathEntries(); + for (IClasspathEntry cpe : entries) { + handleCPE(cpe, javaProject, wsRoot, resMarker); + } + } + } catch (JavaModelException jme) { + // can't resolve the container? ignore it. + AdtPlugin.log(jme, "Failed to resolve ClasspathContainer: %s", entry.getPath()); + } + } } - private void handleClasspathEntry(IClasspathEntry e, IWorkspaceRoot wsRoot, - ArrayList<String> oslibraryList, ResourceMarker resMarker) { + private void handleClasspathLibrary(IClasspathEntry e, IWorkspaceRoot wsRoot, + ResourceMarker resMarker) { // get the IPath IPath path = e.getPath(); @@ -1077,7 +965,7 @@ public class BuildHelper { // case of a jar file (which could be relative to the workspace or a full path) if (resource != null && resource.exists() && resource.getType() == IResource.FILE) { - oslibraryList.add(resource.getLocation().toOSString()); + mCompiledCodePaths.add(resource.getLocation().toOSString()); } 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. @@ -1085,7 +973,7 @@ public class BuildHelper { File f = new File(osFullPath); if (f.isFile()) { - oslibraryList.add(osFullPath); + mCompiledCodePaths.add(osFullPath); } else { String message = String.format( Messages.Couldnt_Locate_s_Error, path); @@ -1102,7 +990,7 @@ public class BuildHelper { // this can be the case for a class folder. if (resource != null && resource.exists() && resource.getType() == IResource.FOLDER) { - oslibraryList.add(resource.getLocation().toOSString()); + mCompiledCodePaths.add(resource.getLocation().toOSString()); } else { // if the path doesn't match a workspace resource, // then we get an OSString and check if this links to a valid folder. @@ -1110,53 +998,13 @@ public class BuildHelper { File f = new File(osFullPath); if (f.isDirectory()) { - oslibraryList.add(osFullPath); + mCompiledCodePaths.add(osFullPath); } } } } /** - * Returns the list of the output folders for the specified {@link IJavaProject} objects, if - * they are Android projects. - * - * @param referencedJavaProjects the java projects. - * @return a new list object containing the output folder paths. - * @throws CoreException - */ - private List<String> getProjectJavaOutputs(List<IJavaProject> referencedJavaProjects) - throws CoreException { - ArrayList<String> list = new ArrayList<String>(); - - IWorkspace ws = ResourcesPlugin.getWorkspace(); - IWorkspaceRoot wsRoot = ws.getRoot(); - - for (IJavaProject javaProject : referencedJavaProjects) { - // only include output from non android referenced project - // (This is to handle the case of reference Android projects in the context of - // instrumentation projects that need to reference the projects to be tested). - if (javaProject.getProject().hasNature(AdtConstants.NATURE_DEFAULT) == false) { - // get the output folder - IPath path = null; - try { - path = javaProject.getOutputLocation(); - } catch (JavaModelException e) { - continue; - } - - IResource outputResource = wsRoot.findMember(path); - if (outputResource != null && outputResource.getType() == IResource.FOLDER) { - String outputOsPath = outputResource.getLocation().toOSString(); - - list.add(outputOsPath); - } - } - } - - return list; - } - - /** * Checks a {@link IFile} to make sure it should be packaged as standard resources. * @param file the IFile representing the file. * @return true if the file should be packaged as standard java resources. diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DexWrapper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DexWrapper.java index e03a150..015d230 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DexWrapper.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DexWrapper.java @@ -30,6 +30,7 @@ import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; +import java.util.Collection; /** * Wrapper to access dx.jar through reflection. @@ -144,7 +145,7 @@ public final class DexWrapper { * @return the integer return code of com.android.dx.command.dexer.Main.run() * @throws CoreException */ - public synchronized int run(String osOutFilePath, String[] osFilenames, + public synchronized int run(String osOutFilePath, Collection<String> osFilenames, boolean verbose, PrintStream outStream, PrintStream errStream) throws CoreException { assert mRunMethod != null; @@ -171,7 +172,7 @@ public final class DexWrapper { // create the Arguments object. Object args = mArgConstructor.newInstance(); mArgOutName.set(args, osOutFilePath); - mArgFileNames.set(args, osFilenames); + mArgFileNames.set(args, osFilenames.toArray(new String[osFilenames.size()])); mArgJarOutput.set(args, false); mArgVerbose.set(args, verbose); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerBuilder.java index 6c4eca4..8be6863 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerBuilder.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerBuilder.java @@ -38,6 +38,7 @@ import com.android.ide.eclipse.adt.internal.sdk.Sdk; import com.android.ide.eclipse.adt.io.IFileWrapper; import com.android.prefs.AndroidLocation.AndroidLocationException; import com.android.sdklib.SdkConstants; +import com.android.sdklib.build.ApkBuilder; import com.android.sdklib.build.ApkCreationException; import com.android.sdklib.build.DuplicateFileException; import com.android.sdklib.build.IArchiveBuilder; @@ -68,6 +69,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.jar.Attributes; @@ -427,7 +429,8 @@ public class PostCompilerBuilder extends BaseBuilder { BuildHelper helper = new BuildHelper(project, mOutStream, mErrStream, true /*debugMode*/, - AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE); + AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE, + mResourceMarker); updateCrunchCache(project, helper); // refresh recursively bin/res folder @@ -542,7 +545,8 @@ public class PostCompilerBuilder extends BaseBuilder { BuildHelper helper = new BuildHelper(project, mOutStream, mErrStream, true /*debugMode*/, - AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE); + AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE, + mResourceMarker); // resource to the AndroidManifest.xml file IFile manifestFile = project.getFile(SdkConstants.FN_ANDROID_MANIFEST_XML); @@ -637,8 +641,7 @@ public class PostCompilerBuilder extends BaseBuilder { System.out.println("\trunning dex!"); } try { - String[] dxInputPaths = helper.getCompiledCodePaths( - true /*includeProjectOutputs*/, mResourceMarker); + Collection<String> dxInputPaths = helper.getCompiledCodePaths(); helper.executeDx(javaProject, dxInputPaths, classesDexPath); } catch (DexException e) { @@ -677,8 +680,7 @@ public class PostCompilerBuilder extends BaseBuilder { } helper.finalDebugPackage( osAndroidBinPath + File.separator + AdtConstants.FN_RESOURCES_AP_, - classesDexPath, osFinalPackagePath, - javaProject, libProjects, referencedJavaProjects, mResourceMarker); + classesDexPath, osFinalPackagePath, libProjects, mResourceMarker); } catch (KeytoolException e) { String eMessage = e.getMessage(); @@ -920,8 +922,8 @@ public class PostCompilerBuilder extends BaseBuilder { // write the class files writeClassFilesIntoJar(jarBuilder, javaOutputFolder, javaOutputFolder); - // now write the standard Java resources - BuildHelper.writeResources(jarBuilder, JavaCore.create(project)); + // now write the standard Java resources from the output folder + ApkBuilder.addSourceFolder(jarBuilder, javaOutputFolder.getLocation().toFile()); saveProjectBooleanProperty(PROPERTY_CONVERT_TO_DEX, mConvertToDex); } catch (Exception e) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/common/CommonXmlEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/common/CommonXmlEditor.java index 5481456..96ce82b 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/common/CommonXmlEditor.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/common/CommonXmlEditor.java @@ -136,10 +136,19 @@ public class CommonXmlEditor extends AndroidXmlEditor implements IShowEditorInpu ResourceFolder resFolder = ResourceManager.getInstance().getResourceFolder(file); ResourceFolderType type = resFolder == null ? null : resFolder.getType(); - for (IDelegateCreator creator : DELEGATES) { - mDelegate = creator.createForFile(this, type); - if (mDelegate != null) { - break; + if (type == null) { + // We lack any real resource information about that file. + // Let's take a guess using the actual path. + String folderName = AdtUtils.getParentFolderName(editorInput); + type = ResourceFolderType.getFolderType(folderName); + } + + if (type != null) { + for (IDelegateCreator creator : DELEGATES) { + mDelegate = creator.createForFile(this, type); + if (mDelegate != null) { + break; + } } } @@ -161,7 +170,7 @@ public class CommonXmlEditor extends AndroidXmlEditor implements IShowEditorInpu // and IProjects so for now just use a plain XML editor for project-less layout // files mDelegate = new OtherXmlEditorDelegate(this); - } else { + } else if (type != null) { for (IDelegateCreator creator : DELEGATES) { mDelegate = creator.createForFile(this, type); if (mDelegate != null) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java index 93fe43d..86c9b22 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java @@ -20,7 +20,6 @@ import static com.android.sdklib.internal.project.ProjectProperties.PROPERTY_SDK import com.android.ide.eclipse.adt.AdtConstants; import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.AdtUtils; import com.android.ide.eclipse.adt.AndroidPrintStream; import com.android.ide.eclipse.adt.internal.build.BuildHelper; import com.android.ide.eclipse.adt.internal.build.DexException; @@ -62,6 +61,8 @@ import java.io.OutputStream; import java.security.PrivateKey; import java.security.cert.X509Certificate; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; @@ -122,7 +123,8 @@ public final class ExportHelper { BuildHelper helper = new BuildHelper(project, fakeStream, fakeStream, - debugMode, false /*verbose*/); + debugMode, false /*verbose*/, + null /*resourceMarker*/); // get the list of library projects ProjectState projectState = Sdk.getProjectState(project); @@ -200,50 +202,51 @@ public final class ExportHelper { } } - String[] dxInput; + Collection<String> dxInput; if (runProguard) { - // the output of the main project (and any java-only project dependency) - String[] projectOutputs = helper.getProjectJavaOutputs(); + // get all the compiled code paths. This will contain both project output + // folder and jar files. + Collection<String> paths = helper.getCompiledCodePaths(); - // create a jar from the output of these projects + // create a jar file containing all the project output (as proguard cannot + // process folders of .class files). File inputJar = File.createTempFile(TEMP_PREFIX, AdtConstants.DOT_JAR); inputJar.deleteOnExit(); - JarOutputStream jos = new JarOutputStream(new FileOutputStream(inputJar)); - for (String po : projectOutputs) { - File root = new File(po); - if (root.exists()) { + + // a list of the other paths (jar files.) + List<String> jars = new ArrayList<String>(); + + for (String path : paths) { + File root = new File(path); + if (root.isDirectory()) { addFileToJar(jos, root, root); + } else if (root.isFile()) { + jars.add(path); } } jos.close(); - // get the other jar files - String[] jarFiles = helper.getCompiledCodePaths(false /*includeProjectOutputs*/, - null /*resourceMarker*/); - // destination file for proguard File obfuscatedJar = File.createTempFile(TEMP_PREFIX, AdtConstants.DOT_JAR); obfuscatedJar.deleteOnExit(); // run proguard - helper.runProguard(proguardConfigFiles, inputJar, jarFiles, obfuscatedJar, + helper.runProguard(proguardConfigFiles, inputJar, jars, obfuscatedJar, new File(project.getLocation().toFile(), SdkConstants.FD_PROGUARD)); + helper.setProguardOutput(obfuscatedJar.getAbsolutePath()); + // dx input is proguard's output - dxInput = new String[] { obfuscatedJar.getAbsolutePath() }; + dxInput = Collections.singletonList(obfuscatedJar.getAbsolutePath()); } else { // no proguard, simply get all the compiled code path: project output(s) + // jar file(s) - dxInput = helper.getCompiledCodePaths(true /*includeProjectOutputs*/, - null /*resourceMarker*/); + dxInput = helper.getCompiledCodePaths(); } IJavaProject javaProject = JavaCore.create(project); - List<IProject> javaProjects = ProjectHelper.getReferencedProjects(project); - List<IJavaProject> referencedJavaProjects = BuildHelper.getJavaProjects( - javaProjects); helper.executeDx(javaProject, dxInput, dexFile.getAbsolutePath()); @@ -253,9 +256,7 @@ public final class ExportHelper { resourceFile.getAbsolutePath(), dexFile.getAbsolutePath(), outputFile.getAbsolutePath(), - javaProject, libProjects, - referencedJavaProjects, key, certificate, null); //resourceMarker @@ -370,17 +371,12 @@ public final class ExportHelper { private static void addFileToJar(JarOutputStream jar, File file, File rootDirectory) throws IOException { if (file.isDirectory()) { - for (File child: file.listFiles()) { - addFileToJar(jar, child, rootDirectory); + if (file.getName().equals("META-INF") == false) { + for (File child: file.listFiles()) { + addFileToJar(jar, child, rootDirectory); + } } - } else if (file.isFile()) { - // check the extension - String name = file.getName(); - if (!AdtUtils.endsWith(name, AdtConstants.DOT_CLASS)) { - return; - } - String rootPath = rootDirectory.getAbsolutePath(); String path = file.getAbsolutePath(); path = path.substring(rootPath.length()).replace("\\", "/"); //$NON-NLS-1$ //$NON-NLS-2$ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/LibraryClasspathContainerInitializer.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/LibraryClasspathContainerInitializer.java index 65fd9c7..c2f2510 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/LibraryClasspathContainerInitializer.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/LibraryClasspathContainerInitializer.java @@ -214,17 +214,16 @@ public class LibraryClasspathContainerInitializer extends BaseClasspathContainer entries.add(entry); - // now, gather the content of this library project's libs folder. + // process all of the library project's dependencies + getDependencyListFromClasspath(libProject, refProjects, jarFiles, true); + // and the content of its libs folder. getJarListFromLibsFolder(libProject, jarFiles); } - - // get project dependencies - processReferencedProjects(libProject, refProjects, jarFiles); } - // now process this projects' referenced projects + // now process this projects' referenced projects only. processReferencedProjects(iProject, refProjects, jarFiles); - // and its own jar files from libs + // and the content of its libs folder getJarListFromLibsFolder(iProject, jarFiles); // annotations support for older version of android @@ -288,30 +287,6 @@ public class LibraryClasspathContainerInitializer extends BaseClasspathContainer IClasspathContainer.K_APPLICATION); } - - private static void processReferencedProjects(IProject project, - Set<IProject> projects, Set<File> jarFiles) { - try { - IProject[] refs = project.getReferencedProjects(); - for (IProject p : refs) { - // ignore if it's an Android project, or if it's not a Java Project - if (p.hasNature(JavaCore.NATURE_ID) && - p.hasNature(AdtConstants.NATURE_DEFAULT) == false) { - // add this project to the list - projects.add(p); - - // get the jar dependencies of the project in the list - getJarListFromClasspath(p, jarFiles); - - // and then process the referenced project by this project too. - processReferencedProjects(p, projects, jarFiles); - } - } - } catch (CoreException e) { - // can't get the referenced projects? ignore - } - } - /** * Finds all the jar files inside a project's libs folder. * @param project @@ -335,13 +310,45 @@ public class LibraryClasspathContainerInitializer extends BaseClasspathContainer } /** - * Finds all the jars a given project depends on by looking at the classpath. - * This must be a non android project, as android project have container that really - * we shouldn't go through. + * Process reference projects from the main projects to add indirect dependencies coming + * from Java project. + * @param project the main project + * @param projects the project list to add to + * @param jarFiles the jar list to add to. + */ + private static void processReferencedProjects(IProject project, + Set<IProject> projects, Set<File> jarFiles) { + try { + IProject[] refs = project.getReferencedProjects(); + for (IProject p : refs) { + // ignore if it's an Android project, or if it's not a Java + // Project + if (p.hasNature(JavaCore.NATURE_ID) + && p.hasNature(AdtConstants.NATURE_DEFAULT) == false) { + + // process this project's dependencies + getDependencyListFromClasspath(p, projects, jarFiles, true /*includeJarFiles*/); + } + } + } catch (CoreException e) { + // can't get the referenced projects? ignore + } + } + + /** + * Finds all the dependencies of a given project and add them to a project list and + * a jar list. + * Only classpath entries that are exported are added, and only Java project (not Android + * project) are added. + * * @param project the project to query - * @param jarFiles the list of file to fill. + * @param projects the referenced project list to add to + * @param jarFiles the jar list to add to + * @param includeJarFiles whether to include jar files or just projects. This is useful when + * calling on an Android project (value should be <code>false</code>) */ - private static void getJarListFromClasspath(IProject project, Set<File> jarFiles) { + private static void getDependencyListFromClasspath(IProject project, Set<IProject> projects, + Set<File> jarFiles, boolean includeJarFiles) { IJavaProject javaProject = JavaCore.create(project); IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot(); @@ -350,38 +357,70 @@ public class LibraryClasspathContainerInitializer extends BaseClasspathContainer IClasspathEntry[] classpaths = javaProject.readRawClasspath(); if (classpaths != null) { for (IClasspathEntry e : classpaths) { - // only consider the classpath entries that are exported. - if (e.isExported() == false) { - continue; - } - // if this is a classpath variable reference, we resolve it. - if (e.getEntryKind() == IClasspathEntry.CPE_VARIABLE) { - e = JavaCore.getResolvedClasspathEntry(e); + // ignore entries that are not exported + if (e.isExported()) { + processCPE(e, javaProject, wsRoot, projects, jarFiles, includeJarFiles); } + } + } + } - if (e.getEntryKind() == IClasspathEntry.CPE_LIBRARY) { - handleClasspathEntry(e, wsRoot, jarFiles); - } else if (e.getEntryKind() == IClasspathEntry.CPE_CONTAINER) { - // get the container. - try { - IClasspathContainer container = JavaCore.getClasspathContainer( - e.getPath(), javaProject); - // ignore the system and default_system types as they represent - // libraries that are part of the runtime. - if (container != null && - container.getKind() == IClasspathContainer.K_APPLICATION) { - IClasspathEntry[] entries = container.getClasspathEntries(); - for (IClasspathEntry entry : entries) { - if (entry.isExported()) { - handleClasspathEntry(entry, wsRoot, jarFiles); - } - } - } - } catch (JavaModelException jme) { - // can't resolve the container? ignore it. - AdtPlugin.log(jme, "Failed to resolve ClasspathContainer: %s", e.getPath()); + /** + * Processes a {@link IClasspathEntry} and add it to one of the list if applicable. + * @param entry the entry to process + * @param javaProject the {@link IJavaProject} from which this entry came. + * @param wsRoot the {@link IWorkspaceRoot} + * @param projects the project list to add to + * @param jarFiles the jar list to add to + * @param includeJarFiles whether to include jar files or just projects. This is useful when + * calling on an Android project (value should be <code>false</code>) + */ + private static void processCPE(IClasspathEntry entry, IJavaProject javaProject, + IWorkspaceRoot wsRoot, + Set<IProject> projects, Set<File> jarFiles, boolean includeJarFiles) { + + // if this is a classpath variable reference, we resolve it. + if (entry.getEntryKind() == IClasspathEntry.CPE_VARIABLE) { + entry = JavaCore.getResolvedClasspathEntry(entry); + } + + if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) { + IProject refProject = wsRoot.getProject(entry.getPath().lastSegment()); + try { + // ignore if it's an Android project, or if it's not a Java Project + if (refProject.hasNature(JavaCore.NATURE_ID) && + refProject.hasNature(AdtConstants.NATURE_DEFAULT) == false) { + // add this project to the list + projects.add(refProject); + + // also get the dependency from this project. + getDependencyListFromClasspath(refProject, projects, jarFiles, + true /*includeJarFiles*/); + } + } catch (CoreException exception) { + // can't query the project nature? ignore + } + } else if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) { + if (includeJarFiles) { + handleClasspathLibrary(entry, wsRoot, jarFiles); + } + } else if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) { + // get the container and its content + try { + IClasspathContainer container = JavaCore.getClasspathContainer( + entry.getPath(), javaProject); + // ignore the system and default_system types as they represent + // libraries that are part of the runtime. + if (container != null && + container.getKind() == IClasspathContainer.K_APPLICATION) { + IClasspathEntry[] entries = container.getClasspathEntries(); + for (IClasspathEntry cpe : entries) { + processCPE(cpe, javaProject, wsRoot, projects, jarFiles, includeJarFiles); } } + } catch (JavaModelException jme) { + // can't resolve the container? ignore it. + AdtPlugin.log(jme, "Failed to resolve ClasspathContainer: %s", entry.getPath()); } } } @@ -406,7 +445,7 @@ public class LibraryClasspathContainerInitializer extends BaseClasspathContainer } } - private static void handleClasspathEntry(IClasspathEntry e, IWorkspaceRoot wsRoot, + private static void handleClasspathLibrary(IClasspathEntry e, IWorkspaceRoot wsRoot, Set<File> jarFiles) { // get the IPath IPath path = e.getPath(); |