diff options
author | Josiah Gaskin <josiahgaskin@google.com> | 2011-08-18 14:28:16 -0700 |
---|---|---|
committer | Android Code Review <code-review@android.com> | 2011-08-18 14:28:16 -0700 |
commit | 239dc46e3f5e80b78ef237a806cc903c83f9e534 (patch) | |
tree | 27f9ccafc1515ebd94cc11f61a9b5ddb4b2bc9f6 | |
parent | 15e9f6bbf0819aae5248337b313492b5cf6241ae (diff) | |
parent | 882e673462566249a538d72b16917bc6cac8315d (diff) | |
download | sdk-239dc46e3f5e80b78ef237a806cc903c83f9e534.zip sdk-239dc46e3f5e80b78ef237a806cc903c83f9e534.tar.gz sdk-239dc46e3f5e80b78ef237a806cc903c83f9e534.tar.bz2 |
Merge "Precompilation only executes AAPT when necessary"
10 files changed, 173 insertions, 66 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/build_messages.properties b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/build_messages.properties index aabe2a4..28ceebd 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/build_messages.properties +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/build_messages.properties @@ -37,7 +37,7 @@ AIDL_Java_Conflict=%1$s is in the way of %2$s, remove it or rename of one the fi AIDL_Exec_Error=Error executing aidl. Please check aidl is present at %1$s s_Removed_Recreating_s=%1$s was removed\! Recreating %1$s\! s_Modified_Manually_Recreating_s=%1$s was modified manually\! Reverting to generated version\! -s_Modified_Recreating_s='%1$s' was modified, %2$s needs to be updated. +s_Modified_Recreating_s='%1$s' was modified. Added_s_s_Needs_Updating=New resource file: '%1$s', %2$s needs to be updated. s_Removed_s_Needs_Updating='%1$s' was removed, %2$s needs to be updated. Requires_Compiler_Compliance_s=Android requires compiler compliance level 5.0 or 6.0. Found '%1$s' instead. Please use Android Tools > Fix Project Properties. diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java index 2a988d1..3ece0e5 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java @@ -255,10 +255,15 @@ public class PreCompilerBuilder extends BaseBuilder { dv = new PreCompilerDeltaVisitor(this, sourceFolderPathList, mProcessors); delta.accept(dv); // Notify the ResourceManager: - ResourceManager.getInstance().processDelta(delta); + ResourceManager resManager = ResourceManager.getInstance(); + resManager.processDelta(delta); - // record the state + // Check whether this project or its dependencies (libraries) have + // resources that need compilation + mMustCompileResources |= resManager.projectNeedsIdGeneration(project); + // Check to see if Manifest.xml, Manifest.java, or R.java have changed: mMustCompileResources |= dv.getCompileResources(); + for (SourceProcessor processor : mProcessors) { processor.doneVisiting(project); } @@ -266,24 +271,6 @@ public class PreCompilerBuilder extends BaseBuilder { // get the java package from the visitor javaPackage = dv.getManifestPackage(); minSdkVersion = dv.getMinSdkVersion(); - - // if the main resources didn't change, then we check for the library - // ones (will trigger resource recompilation too) - if (mMustCompileResources == false && libProjects.size() > 0) { - for (IProject libProject : libProjects) { - delta = getDelta(libProject); - if (delta != null) { - LibraryDeltaVisitor visitor = new LibraryDeltaVisitor(); - delta.accept(visitor); - - mMustCompileResources = visitor.getResChange(); - - if (mMustCompileResources) { - break; - } - } - } - } } } @@ -496,6 +483,7 @@ public class PreCompilerBuilder extends BaseBuilder { handleResources(project, javaPackage, projectTarget, manifestFile, libProjects, projectState.isLibrary()); saveProjectBooleanProperty(PROPERTY_COMPILE_RESOURCES , false); + // The project resources will find out that they're in sync when their IDs are set } if (processorStatus == SourceProcessor.COMPILE_STATUS_NONE && diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerDeltaVisitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerDeltaVisitor.java index cd99fbe..5f08856 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerDeltaVisitor.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerDeltaVisitor.java @@ -16,11 +16,11 @@ package com.android.ide.eclipse.adt.internal.build.builders; -import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.AdtConstants; +import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.internal.build.Messages; import com.android.ide.eclipse.adt.internal.build.SourceChangeHandler; import com.android.ide.eclipse.adt.internal.build.SourceProcessor; -import com.android.ide.eclipse.adt.internal.build.Messages; import com.android.ide.eclipse.adt.internal.build.builders.BaseBuilder.BaseDeltaVisitor; import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity; import com.android.ide.eclipse.adt.internal.project.AndroidManifestHelper; @@ -60,9 +60,8 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements IResourceDelta // Result fields. /** * Compile flag. This is set to true if one of the changed/added/removed - * file is a resource file. Upon visiting all the delta resources, if - * this flag is true, then we know we'll have to compile the resources - * into R.java + * files is Manifest.xml, Manifest.java, or R.java. All other file changes + * will be taken care of by ResourceManager. */ private boolean mCompileResources = false; @@ -88,12 +87,12 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements IResourceDelta private IFolder mSourceFolder = null; /** List of source folders. */ - private List<IPath> mSourceFolders; + private final List<IPath> mSourceFolders; private boolean mIsGenSourceFolder = false; private final List<SourceChangeHandler> mSourceChangeHandlers = new ArrayList<SourceChangeHandler>(); - private IWorkspaceRoot mRoot; + private final IWorkspaceRoot mRoot; @@ -109,6 +108,10 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements IResourceDelta } } + /** + * Get whether Manifest.java, Manifest.xml, or R.java have changed + * @return true if any of Manifest.xml, Manifest.java, or R.java have been modified + */ public boolean getCompileResources() { return mCompileResources; } @@ -323,8 +326,7 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements IResourceDelta switch (kind) { case IResourceDelta.CHANGED: // display verbose message - message = String.format(Messages.s_Modified_Recreating_s, p, - AdtConstants.FN_RESOURCE_CLASS); + message = String.format(Messages.s_Modified_Recreating_s, p); break; case IResourceDelta.ADDED: // display verbose message @@ -345,26 +347,13 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements IResourceDelta for (SourceChangeHandler handler : mSourceChangeHandlers) { handler.handleResourceFile((IFile)resource, kind); } - - if (AdtConstants.EXT_XML.equalsIgnoreCase(ext)) { - if (kind != IResourceDelta.REMOVED) { - // check xml Validity - mBuilder.checkXML(resource, this); - } - - // if we are going through this resource, it was modified - // somehow. - // we don't care if it was an added/removed/changed event - mCompileResources = true; - return false; - } else { - // this is a non xml resource. - if (kind == IResourceDelta.ADDED - || kind == IResourceDelta.REMOVED) { - mCompileResources = true; - return false; - } + // If it's an XML resource, check the syntax + if (AdtConstants.EXT_XML.equalsIgnoreCase(ext) && kind != IResourceDelta.REMOVED) { + // check xml Validity + mBuilder.checkXML(resource, this); } + // Whether or not to generate R.java for a changed resource is taken care of by the + // Resource Manager. } else if (resource instanceof IFolder) { // in this case we may be inside a folder that contains a source // folder, go through the list of known source folders diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/CompiledResourcesMonitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/CompiledResourcesMonitor.java index c917d1c..6ef1710 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/CompiledResourcesMonitor.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/CompiledResourcesMonitor.java @@ -32,7 +32,6 @@ import org.eclipse.core.resources.IMarkerDelta; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceDelta; -import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; @@ -79,9 +78,7 @@ public final class CompiledResourcesMonitor implements IFileListener, IProjectLi * @see IFileListener#fileChanged */ public void fileChanged(IFile file, IMarkerDelta[] markerDeltas, int kind) { - // Don't execute if we're autobuilding, let the precompiler take care of the delta - if (file.getName().equals(AdtConstants.FN_COMPILED_RESOURCE_CLASS) - && ResourcesPlugin.getWorkspace().getDescription().isAutoBuilding() == false) { + if (file.getName().equals(AdtConstants.FN_COMPILED_RESOURCE_CLASS)) { loadAndParseRClass(file.getProject()); } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectResources.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectResources.java index 6d15f89..6967e67 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectResources.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectResources.java @@ -72,7 +72,6 @@ public class ProjectResources extends ResourceRepository { private final IProject mProject; - /** * Makes a ProjectResources for a given <var>project</var>. * @param project the project. @@ -288,5 +287,9 @@ public class ProjectResources extends ResourceRepository { mResourceValueMap = resourceValueMap; mResIdValueToNameMap = resIdValueToNameMap; mStyleableValueToNameMap = styleableValueMap; + + // Our resource IDs should now be in sync + setIdsRefreshed(); } + } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceManager.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceManager.java index c014601..edf55cd 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceManager.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceManager.java @@ -26,6 +26,8 @@ import com.android.ide.eclipse.adt.internal.resources.ResourceHelper; import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor.IProjectListener; import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor.IRawDeltaListener; import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor.IResourceEventListener; +import com.android.ide.eclipse.adt.internal.sdk.ProjectState; +import com.android.ide.eclipse.adt.internal.sdk.Sdk; import com.android.ide.eclipse.adt.io.IFileWrapper; import com.android.ide.eclipse.adt.io.IFolderWrapper; import com.android.io.FolderWrapper; @@ -337,10 +339,10 @@ public final class ResourceManager { return; } - // checks if the file is under res/something. + // checks if the file is under res/something or bin/res/something IPath path = file.getFullPath(); - if (path.segmentCount() == 4) { + if (path.segmentCount() == 4 || path.segmentCount() == 5) { if (isInResFolder(path)) { IContainer container = file.getParent(); if (container instanceof IFolder) { @@ -464,6 +466,50 @@ public final class ResourceManager { } /** + * Checks the ResourceRepositories associated with the given project and its dependencies + * and returns whether or not a resource regeneration is needed for that project + * @param project the project to check + * @return true if the project or any of its dependencies says it has new or deleted resources + */ + public boolean projectNeedsIdGeneration(IProject project) { + // Get a list of repositories to check through + List<ProjectResources> repositories = getAllProjectResourcesAssociatedWith(project); + for (ProjectResources repository : repositories) { + if (repository.needsIdRefresh()) { + return true; + } + } + // If we've gotten to here, all repositories are in sync, return false + return false; + } + + /** + * Get all the resource repositories representing this project and any included libraries + * @param project the project to get along with its dependencies + * @return a list of all ProjectResources ordered lowest to highest priority that need to be + * included in this project. + */ + private List<ProjectResources> getAllProjectResourcesAssociatedWith(IProject project) { + List<ProjectResources> toRet = new ArrayList<ProjectResources>(); + // if the project contains libraries, we need to add the libraries resources here + if (project != null) { + ProjectState state = Sdk.getProjectState(project); + if (state != null) { + List<IProject> libraries = state.getFullLibraryProjects(); + for (IProject library : libraries) { + ProjectResources libRes = mMap.get(library); + if (libRes != null) { + toRet.add(libRes); + } + } + } + } + // Add the queried current project last + toRet.add(mMap.get(project)); + return toRet; + } + + /** * Initial project parsing to gather resource info. * @param project */ diff --git a/ide_common/src/com/android/ide/common/resources/IdGeneratingResourceFile.java b/ide_common/src/com/android/ide/common/resources/IdGeneratingResourceFile.java index fa8d0e7..6706715 100644 --- a/ide_common/src/com/android/ide/common/resources/IdGeneratingResourceFile.java +++ b/ide_common/src/com/android/ide/common/resources/IdGeneratingResourceFile.java @@ -31,6 +31,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; +import java.util.Set; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; @@ -88,8 +89,8 @@ public final class IdGeneratingResourceFile extends ResourceFile @Override protected void update() { - // remove this file from all existing ResourceItem. - getFolder().getRepository().removeFile(mResourceTypeList, this); + // Copy the previous list of ID names + Set<String> oldIdNames = mIdResources.keySet(); // reset current content. mIdResources.clear(); @@ -97,14 +98,21 @@ public final class IdGeneratingResourceFile extends ResourceFile // need to parse the file and find the IDs. parseFileForIds(); - // Notify the repository about any changes - updateResourceItems(); + // We only need to update the repository if our IDs have changed + if (oldIdNames.equals(mIdResources.keySet()) == false) { + updateResourceItems(); + } } @Override protected void dispose() { + ResourceRepository repository = getRepository(); + // Remove declarations from this file from the repository - getFolder().getRepository().removeFile(mResourceTypeList, this); + repository.removeFile(mResourceTypeList, this); + + // Ask for an ID refresh since we'll be taking away ID generating items + repository.markForIdRefresh(); } @Override @@ -155,6 +163,9 @@ public final class IdGeneratingResourceFile extends ResourceFile private void updateResourceItems() { ResourceRepository repository = getRepository(); + // remove this file from all existing ResourceItem. + repository.removeFile(mResourceTypeList, this); + // First add this as a layout file ResourceItem item = repository.getResourceItem(mFileType, mFileName); item.add(this); @@ -165,6 +176,9 @@ public final class IdGeneratingResourceFile extends ResourceFile // add this file to the list of files generating ID resources. item.add(this); } + + // Ask the repository for an ID refresh + repository.markForIdRefresh(); } /** diff --git a/ide_common/src/com/android/ide/common/resources/MultiResourceFile.java b/ide_common/src/com/android/ide/common/resources/MultiResourceFile.java index 6d8ca0a..b3e35d9 100644 --- a/ide_common/src/com/android/ide/common/resources/MultiResourceFile.java +++ b/ide_common/src/com/android/ide/common/resources/MultiResourceFile.java @@ -54,6 +54,10 @@ public final class MultiResourceFile extends ResourceFile implements IValueResou super(file, folder); } + // Boolean flag to track whether a named element has been added or removed, thus requiring + // a new ID table to be generated + private boolean mNeedIdRefresh; + @Override protected void load() { // need to parse the file and find the content. @@ -62,14 +66,21 @@ public final class MultiResourceFile extends ResourceFile implements IValueResou // create new ResourceItems for the new content. mResourceTypeList = Collections.unmodifiableCollection(mResourceItems.keySet()); + // We need an ID generation step + mNeedIdRefresh = true; + // create/update the resource items. updateResourceItems(); } @Override protected void update() { - // remove this file from all existing ResourceItem. - getFolder().getRepository().removeFile(mResourceTypeList, this); + // Reset the ID generation flag + mNeedIdRefresh = false; + + // Copy the previous version of our list of ResourceItems and types + Map<ResourceType, Map<String, ResourceValue>> oldResourceItems + = new EnumMap<ResourceType, Map<String, ResourceValue>>(mResourceItems); // reset current content. mResourceItems.clear(); @@ -80,14 +91,34 @@ public final class MultiResourceFile extends ResourceFile implements IValueResou // create new ResourceItems for the new content. mResourceTypeList = Collections.unmodifiableCollection(mResourceItems.keySet()); + // Check to see if any names have changed. If so, mark the flag so updateResourceItems + // can notify the ResourceRepository that an ID refresh is needed + if (oldResourceItems.keySet().equals(mResourceItems.keySet())) { + for (ResourceType type : mResourceTypeList) { + // We just need to check the names of the items. + // If there are new or removed names then we'll have to regenerate IDs + if (mResourceItems.get(type).keySet() + .equals(oldResourceItems.get(type).keySet()) == false) { + mNeedIdRefresh = true; + } + } + } else { + // If our type list is different, obviously the names will be different + mNeedIdRefresh = true; + } // create/update the resource items. updateResourceItems(); } @Override protected void dispose() { + ResourceRepository repository = getRepository(); + // only remove this file from all existing ResourceItem. - getFolder().getRepository().removeFile(mResourceTypeList, this); + repository.removeFile(mResourceTypeList, this); + + // We'll need an ID refresh because we deleted items + repository.markForIdRefresh(); // don't need to touch the content, it'll get reclaimed as this objects disappear. // In the mean time other objects may need to access it. @@ -106,6 +137,10 @@ public final class MultiResourceFile extends ResourceFile implements IValueResou private void updateResourceItems() { ResourceRepository repository = getRepository(); + + // remove this file from all existing ResourceItem. + repository.removeFile(mResourceTypeList, this); + for (ResourceType type : mResourceTypeList) { Map<String, ResourceValue> list = mResourceItems.get(type); @@ -119,6 +154,11 @@ public final class MultiResourceFile extends ResourceFile implements IValueResou } } } + + // If we need an ID refresh, ask the repository for that now + if (mNeedIdRefresh) { + repository.markForIdRefresh(); + } } /** diff --git a/ide_common/src/com/android/ide/common/resources/ResourceRepository.java b/ide_common/src/com/android/ide/common/resources/ResourceRepository.java index fa533cb..4af4a1a 100644 --- a/ide_common/src/com/android/ide/common/resources/ResourceRepository.java +++ b/ide_common/src/com/android/ide/common/resources/ResourceRepository.java @@ -68,6 +68,7 @@ public abstract class ResourceRepository { protected final IntArrayWrapper mWrapper = new IntArrayWrapper(null); + private boolean mNeedsIdRefresh; /** * Makes a resource repository @@ -195,6 +196,29 @@ public abstract class ResourceRepository { protected abstract ResourceItem createResourceItem(String name); /** + * Sets a flag which determines whether aapt needs to be run to regenerate resource IDs + */ + protected void markForIdRefresh() { + mNeedsIdRefresh = true; + } + + /** + * Returns whether this repository has been marked as "dirty"; if one or more of the constituent + * files have declared that the resource item names that they provide have changed. + */ + public boolean needsIdRefresh() { + return mNeedsIdRefresh; + } + + /** + * Indicates that the resources IDs have been regenerated, so the repository is now in a clean + * state + */ + public void setIdsRefreshed() { + mNeedsIdRefresh = false; + } + + /** * Processes a folder and adds it to the list of existing folders. * @param folder the folder to process * @return the ResourceFolder created from this folder, or null if the process failed. diff --git a/ide_common/src/com/android/ide/common/resources/SingleResourceFile.java b/ide_common/src/com/android/ide/common/resources/SingleResourceFile.java index 9c8977e..b589b35 100644 --- a/ide_common/src/com/android/ide/common/resources/SingleResourceFile.java +++ b/ide_common/src/com/android/ide/common/resources/SingleResourceFile.java @@ -41,8 +41,8 @@ public class SingleResourceFile extends ResourceFile { sParserFactory.setNamespaceAware(true); } - private String mResourceName; - private ResourceType mType; + private final String mResourceName; + private final ResourceType mType; private ResourceValue mValue; public SingleResourceFile(IAbstractFile file, ResourceFolder folder) { @@ -79,6 +79,9 @@ public class SingleResourceFile extends ResourceFile { // add this file to the list of files generating this resource item. item.add(this); + + // Ask for an ID refresh since we're adding an item that will generate an ID + getRepository().markForIdRefresh(); } @Override @@ -92,6 +95,9 @@ public class SingleResourceFile extends ResourceFile { // only remove this file from the existing ResourceItem. getFolder().getRepository().removeFile(mType, this); + // Ask for an ID refresh since we're removing an item that previously generated an ID + getRepository().markForIdRefresh(); + // don't need to touch the content, it'll get reclaimed as this objects disappear. // In the mean time other objects may need to access it. } |