Fix to library projects in Eclipse.
- Properly setup source attachment for library jar files.
- Force refresh the bin folder of libraries to make sure main projects
pick up the changes.
- Force update the library container of parent projects when a library is
recompile. This makes sure the parent projects are recompiled when a library
code change.
- Fix how we check the libraries' res folders exist. This ensures we pick up
all the res folders even if Eclipse isn't aware of them due to refresh issues.
Change-Id: Ie4b7ae770cfc782589a983ec654a11a1dfa4ef2d
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 3209ec1..dad3c5c 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
@@ -214,27 +214,30 @@
assetsFolder = null;
}
- IPath cacheLocation = cacheFolder.getLocation();
+ // list of res folder (main project + maybe libraries)
+ ArrayList<String> osResPaths = new ArrayList<String>();
+
IPath resLocation = resFolder.getLocation();
IPath manifestLocation = manifestFile.getLocation();
if (resLocation != null && manifestLocation != null) {
- // list of res folder (main project + maybe libraries)
- ArrayList<String> osResPaths = new ArrayList<String>();
- osResPaths.add(cacheLocation.toOSString()); // PNG crunch cache
- osResPaths.add(resLocation.toOSString()); //main project
- // libraries?
+ // png cache folder first.
+ addFolderToList(osResPaths, cacheFolder);
+
+ // regular res folder next.
+ osResPaths.add(resLocation.toOSString());
+
+ // then libraries
if (libProjects != null) {
for (IProject lib : libProjects) {
+ // png cache folder first
IFolder libCacheFolder = lib.getFolder(AdtConstants.WS_CRUNCHCACHE);
- if (libCacheFolder.exists()) {
- osResPaths.add(libCacheFolder.getLocation().toOSString());
- }
+ addFolderToList(osResPaths, libCacheFolder);
+
+ // regular res folder next.
IFolder libResFolder = lib.getFolder(AdtConstants.WS_RESOURCES);
- if (libResFolder.exists()) {
- osResPaths.add(libResFolder.getLocation().toOSString());
- }
+ addFolderToList(osResPaths, libResFolder);
}
}
@@ -260,6 +263,19 @@
}
/**
+ * Adds os path of a folder to a list only if the folder actually exists.
+ * @param pathList
+ * @param folder
+ */
+ private void addFolderToList(List<String> pathList, IFolder folder) {
+ // use a File instead of the IFolder API to ignore workspace refresh issue.
+ File testFile = new File(folder.getLocation().toOSString());
+ if (testFile.isDirectory()) {
+ pathList.add(testFile.getAbsolutePath());
+ }
+ }
+
+ /**
* Makes a final package signed with the debug key.
*
* Packages the dex files, the temporary resource file into the final package file.
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 6c2af35..f3d546a 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
@@ -31,6 +31,7 @@
import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity;
import com.android.ide.eclipse.adt.internal.project.ApkInstallManager;
import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
+import com.android.ide.eclipse.adt.internal.project.LibraryClasspathContainerInitializer;
import com.android.ide.eclipse.adt.internal.project.ProjectHelper;
import com.android.ide.eclipse.adt.internal.sdk.ProjectState;
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
@@ -294,6 +295,7 @@
// get the android output folder
IFolder androidOutputFolder = BaseProjectHelper.getAndroidOutputFolder(project);
+ IFolder resOutputFolder = androidOutputFolder.getFolder(SdkConstants.FD_RES);
// now we need to get the classpath list
List<IPath> sourceList = BaseProjectHelper.getSourceClasspaths(javaProject);
@@ -410,15 +412,6 @@
mConvertToDex = true;
}
- if (mConvertToDex) { // in this case this means some class files changed and
- // we need to update the jar file.
- IFolder javaOutputFolder = BaseProjectHelper.getJavaOutputFolder(project);
-
- writeLibraryPackage(jarIFile, project, javaOutputFolder,
- referencedJavaProjects);
- saveProjectBooleanProperty(PROPERTY_CONVERT_TO_DEX, mConvertToDex = false);
- }
-
// also update the crunch cache if needed.
if (mUpdateCrunchCache) {
BuildHelper helper = new BuildHelper(project,
@@ -426,6 +419,27 @@
true /*debugMode*/,
AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE);
updateCrunchCache(project, helper);
+
+ // refresh recursively bin/res folder
+ resOutputFolder.refreshLocal(IResource.DEPTH_INFINITE, monitor);
+ }
+
+ if (mConvertToDex) { // in this case this means some class files changed and
+ // we need to update the jar file.
+ IFolder javaOutputFolder = BaseProjectHelper.getJavaOutputFolder(project);
+
+ writeLibraryPackage(jarIFile, project, javaOutputFolder,
+ referencedJavaProjects);
+ saveProjectBooleanProperty(PROPERTY_CONVERT_TO_DEX, mConvertToDex = false);
+
+ // refresh the bin folder content with no recursion to update the library
+ // jar file.
+ androidOutputFolder.refreshLocal(IResource.DEPTH_ONE, monitor);
+
+ // Also update the projects. The only way to force recompile them is to
+ // reset the library container.
+ List<ProjectState> parentProjects = projectState.getParentProjects();
+ LibraryClasspathContainerInitializer.updateProject(parentProjects);
}
return allRefProjects;
@@ -549,6 +563,9 @@
if (updateCrunchCache(project, helper) == false) {
return allRefProjects;
}
+
+ // refresh recursively bin/res folder
+ resOutputFolder.refreshLocal(IResource.DEPTH_INFINITE, monitor);
}
// Check if we need to package the resources.
@@ -690,7 +707,7 @@
// we are done.
- // get the resource to bin
+ // refresh the bin folder content with no recursion.
androidOutputFolder.refreshLocal(IResource.DEPTH_ONE, monitor);
// build has been done. reset the state of the builder
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 6540038..e31d70d 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
@@ -24,6 +24,8 @@
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
@@ -70,6 +72,26 @@
}
}
+ /**
+ * Updates the {@link IJavaProject} objects with new library.
+ * @param androidProjects the projects to update.
+ * @return <code>true</code> if success, <code>false</code> otherwise.
+ */
+ public static boolean updateProject(List<ProjectState> projects) {
+ List<IJavaProject> javaProjectList = new ArrayList<IJavaProject>(projects.size());
+ for (ProjectState p : projects) {
+ IJavaProject javaProject = JavaCore.create(p.getProject());
+ if (javaProject != null) {
+ javaProjectList.add(javaProject);
+ }
+ }
+
+ IJavaProject[] javaProjects = javaProjectList.toArray(
+ new IJavaProject[javaProjectList.size()]);
+
+ return updateProjects(javaProjects);
+ }
+
@Override
public void initialize(IPath containerPath, IJavaProject project) throws CoreException {
if (AdtConstants.CONTAINER_LIBRARIES.equals(containerPath.toString())) {
@@ -132,6 +154,8 @@
List<IClasspathEntry> entries = new ArrayList<IClasspathEntry>();
+ IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
+
List<IProject> libProjects = state.getFullLibraryProjects();
for (IProject libProject : libProjects) {
// get the project output
@@ -141,10 +165,22 @@
IFile jarIFile = outputFolder.getFile(libProject.getName().toLowerCase() +
AdtConstants.DOT_JAR);
+ // get the source folder for the library project
+ List<IPath> srcs = BaseProjectHelper.getSourceClasspaths(libProject);
+ // find the first non-derived source folder.
+ IPath sourceFolder = null;
+ for (IPath src : srcs) {
+ IFolder srcFolder = workspaceRoot.getFolder(src);
+ if (srcFolder.isDerived() == false) {
+ sourceFolder = src;
+ break;
+ }
+ }
+
IClasspathEntry entry = JavaCore.newLibraryEntry(
jarIFile.getLocation(),
- libProject.getLocation(), // source attachment path
- null); // default source attachment root path.
+ sourceFolder, // source attachment path
+ null); // default source attachment root path.
entries.add(entry);
}