diff options
Diffstat (limited to 'eclipse')
23 files changed, 668 insertions, 299 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/.classpath b/eclipse/plugins/com.android.ide.eclipse.adt/.classpath index 91dbcbb..2fd96a4 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/.classpath +++ b/eclipse/plugins/com.android.ide.eclipse.adt/.classpath @@ -14,6 +14,5 @@ <classpathentry kind="lib" path="sdkuilib.jar" sourcepath="/SdkUiLib"/> <classpathentry kind="lib" path="commons-compress-1.0.jar"/> <classpathentry kind="lib" path="groovy-all-1.7.0.jar" sourcepath="/GroovySrc/groovy-src-1.7.0.zip"/> - <classpathentry kind="lib" path="builders.jar"/> <classpathentry kind="output" path="bin"/> </classpath> diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF b/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF index 46d97b5..9a1b9cd 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF +++ b/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF @@ -14,8 +14,7 @@ Bundle-ClassPath: ., sdklib.jar, sdkuilib.jar, commons-compress-1.0.jar, - groovy-all-1.7.0.jar, - builders.jar + groovy-all-1.7.0.jar Bundle-Activator: com.android.ide.eclipse.adt.AdtPlugin Bundle-Vendor: The Android Open Source Project Require-Bundle: com.android.ide.eclipse.ddms, @@ -49,8 +48,7 @@ Require-Bundle: com.android.ide.eclipse.ddms, org.eclipse.ltk.ui.refactoring, org.eclipse.core.expressions Eclipse-LazyStart: true -Export-Package: com.android.builders;x-friends:="com.android.ide.eclipse.tests", - com.android.ide.eclipse.adt;x-friends:="com.android.ide.eclipse.tests", +Export-Package: com.android.ide.eclipse.adt;x-friends:="com.android.ide.eclipse.tests", com.android.ide.eclipse.adt.internal;x-friends:="com.android.ide.eclipse.tests", com.android.ide.eclipse.adt.internal.actions;x-friends:="com.android.ide.eclipse.tests", com.android.ide.eclipse.adt.internal.build;x-friends:="com.android.ide.eclipse.tests", @@ -100,6 +98,7 @@ Export-Package: com.android.builders;x-friends:="com.android.ide.eclipse.tests", com.android.prefs;x-friends:="com.android.ide.eclipse.tests", com.android.sdklib;x-friends:="com.android.ide.eclipse.tests", com.android.sdklib.internal.avd;x-friends:="com.android.ide.eclipse.tests", + com.android.sdklib.internal.io;x-friends:="com.android.ide.eclipse.tests", com.android.sdklib.internal.project;x-friends:="com.android.ide.eclipse.tests", com.android.sdklib.internal.repository;x-friends:="com.android.ide.eclipse.tests", com.android.sdklib.repository;x-friends:="com.android.ide.eclipse.tests", diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/build.properties b/eclipse/plugins/com.android.ide.eclipse.adt/build.properties index ed2a914..47f6611 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/build.properties +++ b/eclipse/plugins/com.android.ide.eclipse.adt/build.properties @@ -15,7 +15,6 @@ bin.includes = plugin.xml,\ sdkuilib.jar,\ commons-compress-1.0.jar,\ groovy-all-1.7.0.jar,\ - gscripts/,\ - builders.jar + gscripts/ source.. = src/ output.. = bin/ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java index af211b9..f52e9c4 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java @@ -34,11 +34,11 @@ import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; import com.android.ide.eclipse.adt.internal.project.ExportHelper; import com.android.ide.eclipse.adt.internal.project.ProjectHelper; import com.android.ide.eclipse.adt.internal.project.ExportHelper.IExportCallback; +import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor; import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResources; import com.android.ide.eclipse.adt.internal.resources.manager.ResourceFolder; import com.android.ide.eclipse.adt.internal.resources.manager.ResourceFolderType; import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager; -import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor; import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor.IFileListener; import com.android.ide.eclipse.adt.internal.sdk.LoadStatus; import com.android.ide.eclipse.adt.internal.sdk.Sdk; @@ -817,25 +817,17 @@ public class AdtPlugin extends AbstractUIPlugin { * Returns whether the {@link IAndroidTarget}s have been loaded from the SDK. */ public final LoadStatus getSdkLoadStatus() { - synchronized (getSdkLockObject()) { + synchronized (Sdk.getLock()) { return mSdkIsLoaded; } } /** - * Returns the lock object for SDK loading. If you wish to do things while the SDK is loading, - * you must synchronize on this object. - */ - public final Object getSdkLockObject() { - return mPostLoadProjectsToResolve; - } - - /** * Sets the given {@link IJavaProject} to have its target resolved again once the SDK finishes * to load. */ public final void setProjectToResolve(IJavaProject javaProject) { - synchronized (getSdkLockObject()) { + synchronized (Sdk.getLock()) { mPostLoadProjectsToResolve.add(javaProject); } } @@ -847,7 +839,7 @@ public class AdtPlugin extends AbstractUIPlugin { */ public final void setProjectToCheck(IJavaProject javaProject) { // only lock on - synchronized (getSdkLockObject()) { + synchronized (Sdk.getLock()) { mPostLoadProjectsToCheck.add(javaProject); } } @@ -984,13 +976,18 @@ public class AdtPlugin extends AbstractUIPlugin { if (sdk != null) { ArrayList<IJavaProject> list = new ArrayList<IJavaProject>(); - synchronized (getSdkLockObject()) { + synchronized (Sdk.getLock()) { mSdkIsLoaded = LoadStatus.LOADED; progress.setTaskName("Check Projects"); for (IJavaProject javaProject : mPostLoadProjectsToResolve) { - if (javaProject.getProject().isOpen()) { + IProject iProject = javaProject.getProject(); + if (iProject.isOpen()) { + // project that have been resolved before the sdk was loaded + // will have a ProjectState where the IAndroidTarget is null + // so we load the target now that the SDK is loaded. + sdk.loadTarget(Sdk.getProject(iProject)); list.add(javaProject); } } @@ -1018,7 +1015,7 @@ public class AdtPlugin extends AbstractUIPlugin { } else { // SDK failed to Load! // Sdk#loadSdk() has already displayed an error. - synchronized (getSdkLockObject()) { + synchronized (Sdk.getLock()) { mSdkIsLoaded = LoadStatus.FAILED; } } @@ -1372,7 +1369,7 @@ public class AdtPlugin extends AbstractUIPlugin { public void reparseSdk() { // add all the opened Android projects to the list of projects to be updated // after the SDK is reloaded - synchronized (getSdkLockObject()) { + synchronized (Sdk.getLock()) { // get the project to refresh. IJavaProject[] androidProjects = BaseProjectHelper.getAndroidProjects(); mPostLoadProjectsToResolve.addAll(Arrays.asList(androidProjects)); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/PreCompilerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/PreCompilerBuilder.java index ee85e1b..e06eda2 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/PreCompilerBuilder.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/PreCompilerBuilder.java @@ -23,7 +23,9 @@ import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity; import com.android.ide.eclipse.adt.internal.project.AndroidManifestParser; import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; import com.android.ide.eclipse.adt.internal.project.FixLaunchConfig; +import com.android.ide.eclipse.adt.internal.project.ProjectState; import com.android.ide.eclipse.adt.internal.project.XmlErrorHandler.BasicXmlErrorListener; +import com.android.ide.eclipse.adt.internal.resources.manager.files.IFolderWrapper; import com.android.ide.eclipse.adt.internal.sdk.Sdk; import com.android.sdklib.AndroidVersion; import com.android.sdklib.IAndroidTarget; @@ -207,21 +209,27 @@ public class PreCompilerBuilder extends BaseBuilder { @Override protected IProject[] build(int kind, Map args, IProgressMonitor monitor) throws CoreException { + // get a project object + IProject project = getProject(); + + // list of referenced projects. + IProject[] libProjects = null; + try { mDerivedProgressMonitor.reset(); - // First thing we do is go through the resource delta to not - // lose it if we have to abort the build for any reason. + // get the project info + ProjectState projectState = Sdk.getProject(project); + IAndroidTarget projectTarget = projectState.getTarget(); + + // get the libraries + libProjects = projectState.getLibraryProjects(); - // get the project objects - IProject project = getProject(); IJavaProject javaProject = JavaCore.create(project); // Top level check to make sure the build can move forward. abortOnBadSetup(javaProject); - IAndroidTarget projectTarget = Sdk.getCurrent().getTarget(project); - // now we need to get the classpath list ArrayList<IPath> sourceFolderPathList = BaseProjectHelper.getSourceClasspaths( javaProject); @@ -452,151 +460,7 @@ public class PreCompilerBuilder extends BaseBuilder { } if (mMustCompileResources) { - // we need to figure out where to store the R class. - // get the parent folder for R.java and update mManifestPackageSourceFolder - IFolder packageFolder = getGenManifestPackageFolder(project); - - // get the resource folder - IFolder resFolder = project.getFolder(AndroidConstants.WS_RESOURCES); - - // get the file system path - IPath outputLocation = mGenFolder.getLocation(); - IPath resLocation = resFolder.getLocation(); - IPath manifestLocation = manifest == null ? null : manifest.getLocation(); - - // those locations have to exist for us to do something! - if (outputLocation != null && resLocation != null - && manifestLocation != null) { - String osOutputPath = outputLocation.toOSString(); - String osResPath = resLocation.toOSString(); - String osManifestPath = manifestLocation.toOSString(); - - // remove the aapt markers - removeMarkersFromFile(manifest, AndroidConstants.MARKER_AAPT_COMPILE); - removeMarkersFromContainer(resFolder, AndroidConstants.MARKER_AAPT_COMPILE); - - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, - Messages.Preparing_Generated_Files); - - // since the R.java file may be already existing in read-only - // mode we need to make it readable so that aapt can overwrite - // it - IFile rJavaFile = packageFolder.getFile(AndroidConstants.FN_RESOURCE_CLASS); - - // do the same for the Manifest.java class - IFile manifestJavaFile = packageFolder.getFile( - AndroidConstants.FN_MANIFEST_CLASS); - - // we actually need to delete the manifest.java as it may become empty and - // in this case aapt doesn't generate an empty one, but instead doesn't - // touch it. - manifestJavaFile.delete(true, null); - - // launch aapt: create the command line - ArrayList<String> array = new ArrayList<String>(); - array.add(projectTarget.getPath(IAndroidTarget.AAPT)); - array.add("package"); //$NON-NLS-1$ - array.add("-m"); //$NON-NLS-1$ - if (AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE) { - array.add("-v"); //$NON-NLS-1$ - } - array.add("-J"); //$NON-NLS-1$ - array.add(osOutputPath); - array.add("-M"); //$NON-NLS-1$ - array.add(osManifestPath); - array.add("-S"); //$NON-NLS-1$ - array.add(osResPath); - array.add("-I"); //$NON-NLS-1$ - array.add(projectTarget.getPath(IAndroidTarget.ANDROID_JAR)); - - if (AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE) { - StringBuilder sb = new StringBuilder(); - for (String c : array) { - sb.append(c); - sb.append(' '); - } - String cmd_line = sb.toString(); - AdtPlugin.printToConsole(project, cmd_line); - } - - // launch - int execError = 1; - try { - // launch the command line process - Process process = Runtime.getRuntime().exec( - array.toArray(new String[array.size()])); - - // list to store each line of stderr - ArrayList<String> results = new ArrayList<String>(); - - // get the output and return code from the process - execError = grabProcessOutput(process, results); - - // attempt to parse the error output - boolean parsingError = parseAaptOutput(results, project); - - // if we couldn't parse the output we display it in the console. - if (parsingError) { - if (execError != 0) { - AdtPlugin.printErrorToConsole(project, results.toArray()); - } else { - AdtPlugin.printBuildToConsole(BuildVerbosity.NORMAL, - project, results.toArray()); - } - } - - if (execError != 0) { - // if the exec failed, and we couldn't parse the error output - // (and therefore not all files that should have been marked, - // were marked), we put a generic marker on the project and abort. - if (parsingError) { - markProject(AndroidConstants.MARKER_ADT, - Messages.Unparsed_AAPT_Errors, IMarker.SEVERITY_ERROR); - } - - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, - Messages.AAPT_Error); - - // abort if exec failed. - // This interrupts the build. The next builders will not run. - stopBuild(Messages.AAPT_Error); - } - } catch (IOException e1) { - // something happen while executing the process, - // mark the project and exit - String msg = String.format(Messages.AAPT_Exec_Error, array.get(0)); - markProject(AndroidConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR); - - // This interrupts the build. The next builders will not run. - stopBuild(msg); - } catch (InterruptedException e) { - // we got interrupted waiting for the process to end... - // mark the project and exit - String msg = String.format(Messages.AAPT_Exec_Error, array.get(0)); - markProject(AndroidConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR); - - // This interrupts the build. The next builders will not run. - stopBuild(msg); - } - - // if the return code was OK, we refresh the folder that - // contains R.java to force a java recompile. - if (execError == 0) { - // now add the R.java/Manifest.java to the list of file to be marked - // as derived. - mDerivedProgressMonitor.addFile(rJavaFile); - mDerivedProgressMonitor.addFile(manifestJavaFile); - - // build has been done. reset the state of the builder - mMustCompileResources = false; - - // and store it - saveProjectBooleanProperty(PROPERTY_COMPILE_RESOURCES, - mMustCompileResources); - } - } - } else { - // nothing to do + handleResources(project, javaPackage, projectTarget, manifest, libProjects); } // now handle the aidl stuff. @@ -612,7 +476,7 @@ public class PreCompilerBuilder extends BaseBuilder { mGenFolder.refreshLocal(IResource.DEPTH_INFINITE, mDerivedProgressMonitor); } - return null; + return libProjects; } @Override @@ -628,7 +492,6 @@ public class PreCompilerBuilder extends BaseBuilder { // remove all the derived resources from the 'gen' source folder. removeDerivedResources(mGenFolder, monitor); - // Clear the project of the generic markers removeMarkersFromProject(project, AndroidConstants.MARKER_AAPT_COMPILE); removeMarkersFromProject(project, AndroidConstants.MARKER_XML); @@ -666,6 +529,231 @@ public class PreCompilerBuilder extends BaseBuilder { } /** + * Handles resource changes and regenerate whatever files need regenerating. + * @param project the main project + * @param javaPackage the app package for the main project + * @param projectTarget the target of the main project + * @param manifest the {@link IFile} representing the project manifest + * @param libProjects the library dependencies + * @throws CoreException + */ + private void handleResources(IProject project, String javaPackage, IAndroidTarget projectTarget, + IFile manifest, IProject[] libProjects) throws CoreException { + // get the resource folder + IFolder resFolder = project.getFolder(AndroidConstants.WS_RESOURCES); + + // get the file system path + IPath outputLocation = mGenFolder.getLocation(); + IPath resLocation = resFolder.getLocation(); + IPath manifestLocation = manifest == null ? null : manifest.getLocation(); + + // those locations have to exist for us to do something! + if (outputLocation != null && resLocation != null + && manifestLocation != null) { + String osOutputPath = outputLocation.toOSString(); + String osResPath = resLocation.toOSString(); + String osManifestPath = manifestLocation.toOSString(); + + // remove the aapt markers + removeMarkersFromFile(manifest, AndroidConstants.MARKER_AAPT_COMPILE); + removeMarkersFromContainer(resFolder, AndroidConstants.MARKER_AAPT_COMPILE); + + AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, + Messages.Preparing_Generated_Files); + + // we need to figure out where to store the R class. + // get the parent folder for R.java and update mManifestPackageSourceFolder + IFolder mainPackageFolder = getGenManifestPackageFolder(); + + // handle libraries + ArrayList<IFolder> libResFolders = new ArrayList<IFolder>(); + ArrayList<IFolder> libOutputFolders = new ArrayList<IFolder>(); + ArrayList<String> libJavaPackages = new ArrayList<String>(); + if (libProjects != null) { + for (IProject lib : libProjects) { + IFolder libResFolder = lib.getFolder(SdkConstants.FD_RES); + if (libResFolder.exists()) { + libResFolders.add(libResFolder); + } + + try { + String libJavaPackage = AndroidManifest.getPackage(new IFolderWrapper(lib)); + if (libJavaPackage.equals(javaPackage) == false) { + libJavaPackages.add(libJavaPackage); + libOutputFolders.add(getGenManifestPackageFolder(libJavaPackage)); + } + } catch (Exception e) { + } + } + } + + execAapt(project, projectTarget, osOutputPath, osResPath, osManifestPath, + mainPackageFolder, libResFolders, null /* custom java package */); + + final int count = libOutputFolders.size(); + if (count > 0) { + for (int i = 0 ; i < count ; i++) { + IFolder libFolder = libOutputFolders.get(i); + String libJavaPackage = libJavaPackages.get(i); + execAapt(project, projectTarget, osOutputPath, osResPath, osManifestPath, + libFolder, libResFolders, libJavaPackage); + } + } + } + } + + /** + * Executes AAPT to generate R.java/Manifest.java + * @param project the main project + * @param projectTarget the main project target + * @param osOutputPath the OS output path for the generated file. This is the source folder, not + * the package folder. + * @param osResPath the OS path to the res folder for the main project + * @param osManifestPath the OS path to the manifest of the main project + * @param packageFolder the IFolder that will contain the generated file. Unlike + * <var>osOutputPath</var> this is the direct parent of the geenerated files. + * If <var>customJavaPackage</var> is not null, this must match the new destination triggered + * by its value. + * @param libResFolders the list of res folders for the library. + * @param customJavaPackage an optional javapackage to replace the main project java package. + * can be null. + * @throws CoreException + */ + private void execAapt(IProject project, IAndroidTarget projectTarget, String osOutputPath, + String osResPath, String osManifestPath, IFolder packageFolder, + ArrayList<IFolder> libResFolders, String customJavaPackage) throws CoreException { + // since the R.java file may be already existing in read-only + // mode we need to make it readable so that aapt can overwrite it + IFile rJavaFile = packageFolder.getFile(AndroidConstants.FN_RESOURCE_CLASS); + + // do the same for the Manifest.java class + IFile manifestJavaFile = packageFolder.getFile(AndroidConstants.FN_MANIFEST_CLASS); + + // we actually need to delete the manifest.java as it may become empty and + // in this case aapt doesn't generate an empty one, but instead doesn't + // touch it. + manifestJavaFile.delete(true, null); + + // launch aapt: create the command line + ArrayList<String> array = new ArrayList<String>(); + array.add(projectTarget.getPath(IAndroidTarget.AAPT)); + array.add("package"); //$NON-NLS-1$ + array.add("-m"); //$NON-NLS-1$ + if (AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE) { + array.add("-v"); //$NON-NLS-1$ + } + + if (libResFolders.size() > 0) { + array.add("--auto-add-overlay"); //$NON-NLS-1$ + } + + if (customJavaPackage != null) { + array.add("--custom-package"); //$NON-NLS-1$ + array.add(customJavaPackage); + } + + array.add("-J"); //$NON-NLS-1$ + array.add(osOutputPath); + array.add("-M"); //$NON-NLS-1$ + array.add(osManifestPath); + array.add("-S"); //$NON-NLS-1$ + array.add(osResPath); + for (IFolder libResFolder : libResFolders) { + array.add("-S"); //$NON-NLS-1$ + array.add(libResFolder.getLocation().toOSString()); + } + + array.add("-I"); //$NON-NLS-1$ + array.add(projectTarget.getPath(IAndroidTarget.ANDROID_JAR)); + + if (AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE) { + StringBuilder sb = new StringBuilder(); + for (String c : array) { + sb.append(c); + sb.append(' '); + } + String cmd_line = sb.toString(); + AdtPlugin.printToConsole(project, cmd_line); + } + + // launch + int execError = 1; + try { + // launch the command line process + Process process = Runtime.getRuntime().exec( + array.toArray(new String[array.size()])); + + // list to store each line of stderr + ArrayList<String> results = new ArrayList<String>(); + + // get the output and return code from the process + execError = grabProcessOutput(process, results); + + // attempt to parse the error output + boolean parsingError = parseAaptOutput(results, project); + + // if we couldn't parse the output we display it in the console. + if (parsingError) { + if (execError != 0) { + AdtPlugin.printErrorToConsole(project, results.toArray()); + } else { + AdtPlugin.printBuildToConsole(BuildVerbosity.NORMAL, + project, results.toArray()); + } + } + + if (execError != 0) { + // if the exec failed, and we couldn't parse the error output + // (and therefore not all files that should have been marked, + // were marked), we put a generic marker on the project and abort. + if (parsingError) { + markProject(AndroidConstants.MARKER_ADT, + Messages.Unparsed_AAPT_Errors, IMarker.SEVERITY_ERROR); + } + + AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, + Messages.AAPT_Error); + + // abort if exec failed. + // This interrupts the build. The next builders will not run. + stopBuild(Messages.AAPT_Error); + } + } catch (IOException e1) { + // something happen while executing the process, + // mark the project and exit + String msg = String.format(Messages.AAPT_Exec_Error, array.get(0)); + markProject(AndroidConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR); + + // This interrupts the build. The next builders will not run. + stopBuild(msg); + } catch (InterruptedException e) { + // we got interrupted waiting for the process to end... + // mark the project and exit + String msg = String.format(Messages.AAPT_Exec_Error, array.get(0)); + markProject(AndroidConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR); + + // This interrupts the build. The next builders will not run. + stopBuild(msg); + } + + // if the return code was OK, we refresh the folder that + // contains R.java to force a java recompile. + if (execError == 0) { + // now add the R.java/Manifest.java to the list of file to be marked + // as derived. + mDerivedProgressMonitor.addFile(rJavaFile); + mDerivedProgressMonitor.addFile(manifestJavaFile); + + // build has been done. reset the state of the builder + mMustCompileResources = false; + + // and store it + saveProjectBooleanProperty(PROPERTY_COMPILE_RESOURCES, + mMustCompileResources); + } + } + + /** * Delete the a generated java class associated with the specified java package. * @param filename Name of the generated file to remove. * @param javaPackage the old java package @@ -720,13 +808,11 @@ public class PreCompilerBuilder extends BaseBuilder { * Returns an {@link IFolder} (located inside the 'gen' source folder), that matches the * package defined in the manifest. This {@link IFolder} may not actually exist * (aapt will create it anyway). - * @param project The project. * @return the {@link IFolder} that will contain the R class or null if * the folder was not found. * @throws CoreException */ - private IFolder getGenManifestPackageFolder(IProject project) - throws CoreException { + private IFolder getGenManifestPackageFolder() throws CoreException { // get the path for the package IPath packagePath = getJavaPackagePath(mManifestPackage); @@ -736,6 +822,24 @@ public class PreCompilerBuilder extends BaseBuilder { } /** + * Returns an {@link IFolder} (located inside the 'gen' source folder), that matches the + * given package. This {@link IFolder} may not actually exist + * (aapt will create it anyway). + * @param javaPackage the java package that must match the folder. + * @return the {@link IFolder} that will contain the R class or null if + * the folder was not found. + * @throws CoreException + */ + private IFolder getGenManifestPackageFolder(String javaPackage) throws CoreException { + // get the path for the package + IPath packagePath = getJavaPackagePath(javaPackage); + + // get a folder for this path under the 'gen' source folder, and return it. + // This IFolder may not reference an actual existing folder. + return mGenFolder.getFolder(packagePath); + } + + /** * Compiles aidl files into java. This will also removes old java files * created from aidl files that are now gone. * @param projectTarget Target of the project diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidClasspathContainerInitializer.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidClasspathContainerInitializer.java index 6f0b157..b03f041 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidClasspathContainerInitializer.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidClasspathContainerInitializer.java @@ -158,9 +158,7 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit try { AdtPlugin plugin = AdtPlugin.getDefault(); - // get the lock object for project manipulation during SDK load. - Object lock = plugin.getSdkLockObject(); - synchronized (lock) { + synchronized (Sdk.getLock()) { boolean sdkIsLoaded = plugin.getSdkLoadStatus() == LoadStatus.LOADED; // check if the project has a valid target. @@ -499,6 +497,7 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit * @param projects the list of projects to check. */ public static void checkProjectsCache(ArrayList<IJavaProject> projects) { + Sdk currentSdk = Sdk.getCurrent(); int i = 0; projectLoop: while (i < projects.size()) { IJavaProject javaProject = projects.get(i); @@ -513,8 +512,13 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit continue; } + // project that have been resolved before the sdk was loaded + // will have a ProjectState where the IAndroidTarget is null + // so we load the target now that the SDK is loaded. + currentSdk.loadTarget(Sdk.getProject(iProject)); + // get the target from the project and its paths - IAndroidTarget target = Sdk.getCurrent().getTarget(javaProject.getProject()); + IAndroidTarget target = currentSdk.getTarget(javaProject.getProject()); if (target == null) { // this is really not supposed to happen. This would mean there are cached paths, // but default.properties was deleted. Keep the project in the list to force diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidManifestParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidManifestParser.java index 189fb81..8bbd018 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidManifestParser.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidManifestParser.java @@ -952,26 +952,4 @@ public class AndroidManifestParser { } return (IFile) r; } - - /** - * Given a fully qualified activity name (e.g. com.foo.test.MyClass) and given a project - * package base name (e.g. com.foo), returns the relative activity name that would be used - * the "name" attribute of an "activity" element. - * - * @param fullActivityName a fully qualified activity class name, e.g. "com.foo.test.MyClass" - * @param packageName The project base package name, e.g. "com.foo" - * @return The relative activity name if it can be computed or the original fullActivityName. - */ - public static String extractActivityName(String fullActivityName, String packageName) { - if (packageName != null && fullActivityName != null) { - if (packageName.length() > 0 && fullActivityName.startsWith(packageName)) { - String name = fullActivityName.substring(packageName.length()); - if (name.length() > 0 && name.charAt(0) == '.') { - return name; - } - } - } - - return fullActivityName; - } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectState.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectState.java index 70af6fd..63d3d2b 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectState.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectState.java @@ -17,11 +17,16 @@ package com.android.ide.eclipse.adt.internal.project; import com.android.sdklib.IAndroidTarget; +import com.android.sdklib.internal.project.ApkConfigurationHelper; import com.android.sdklib.internal.project.ApkSettings; import com.android.sdklib.internal.project.ProjectProperties; import org.eclipse.core.resources.IProject; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; + /** * Centralized state for Android Eclipse project. * <p>This gives raw access to the properties (from <code>default.properties</code>), as well @@ -30,14 +35,61 @@ import org.eclipse.core.resources.IProject; */ public final class ProjectState { + public final class LibraryState { + private final String mRelativePath; + private IProject mProject; + private String mPath; + + private LibraryState(String relativePath) { + mRelativePath = relativePath; + } + + private void setProject(IProject project) { + mProject = project; + mPath = project.getLocation().toOSString(); + + updateLibraries(); + } + + public String getRelativePath() { + return mRelativePath; + } + + public IProject getProject() { + return mProject; + } + + public String getProjectLocation() { + return mPath; + } + } + private final IProject mProject; private final ProjectProperties mProperties; + private final ArrayList<LibraryState> mLibraries = new ArrayList<LibraryState>(); private IAndroidTarget mTarget; private ApkSettings mApkSettings; + private IProject[] mLibraryProjects; public ProjectState(IProject project, ProjectProperties properties) { mProject = project; mProperties = properties; + + // load the ApkSettings + mApkSettings = ApkConfigurationHelper.getSettings(properties); + + // load the libraries + int index = 1; + while (true) { + String propName = ProjectProperties.PROPERTY_LIB_REF + Integer.toString(index++); + String rootPath = mProperties.getProperty(propName); + + if (rootPath == null) { + break; + } + + mLibraries.add(new LibraryState(convertPath(rootPath))); + } } public IProject getProject() { @@ -83,4 +135,78 @@ public final class ProjectState { public ApkSettings getApkSettings() { return mApkSettings; } + + public IProject[] getLibraryProjects() { + return mLibraryProjects; + } + + /** + * Returns whether this is a library project. + */ + public boolean isLibrary() { + String value = mProperties.getProperty(ProjectProperties.PROPERTY_LIBRARY); + return value != null && Boolean.valueOf(value); + } + + /** + * Returns whether the project is missing some required libraries. + */ + public boolean isMissingLibraries() { + for (LibraryState state : mLibraries) { + if (state.getProject() == null) { + return true; + } + } + + return false; + } + + /** + * Returns whether a given library project is needed by the receiver. + * @param libraryProject the library project to check. + * @return a non null object if the project is a library dependency. + */ + public LibraryState needs(IProject libraryProject) { + // compute current location + File projectFile = new File(mProject.getLocation().toOSString()); + + // get the location of the library. + File libraryFile = new File(libraryProject.getLocation().toOSString()); + + // loop on all libraries and check if the path match + for (LibraryState state : mLibraries) { + if (state.getProject() == null) { + File library = new File(projectFile, state.getRelativePath()); + try { + File absPath = library.getCanonicalFile(); + if (absPath.equals(libraryFile)) { + state.setProject(libraryProject); + return state; + } + } catch (IOException e) { + // ignore this library + } + } + } + + return null; + } + + private void updateLibraries() { + ArrayList<IProject> list = new ArrayList<IProject>(); + for (LibraryState state : mLibraries) { + if (state.getProject() != null) { + list.add(state.getProject()); + } + } + + mLibraryProjects = list.toArray(new IProject[list.size()]); + } + + /** + * Converts a path containing only / by the proper platform separator. + */ + private String convertPath(String path) { + return path.replaceAll("/", File.separator); //$NON-NLS-1$ + } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/MultiResourceFile.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/MultiResourceFile.java index 3386e17..047834d 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/MultiResourceFile.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/MultiResourceFile.java @@ -16,13 +16,13 @@ package com.android.ide.eclipse.adt.internal.resources.manager; -import com.android.builders.IAbstractFile; -import com.android.builders.StreamException; import com.android.ide.eclipse.adt.internal.resources.ResourceType; import com.android.layoutlib.api.IResourceValue; import com.android.layoutlib.utils.ResourceValue; import com.android.layoutlib.utils.ValueResourceParser; import com.android.layoutlib.utils.ValueResourceParser.IValueResourceRepository; +import com.android.sdklib.internal.io.IAbstractFile; +import com.android.sdklib.internal.io.StreamException; import org.xml.sax.SAXException; 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 e91ebe5..cb05653 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 @@ -16,7 +16,6 @@ package com.android.ide.eclipse.adt.internal.resources.manager; -import com.android.builders.IAbstractFolder; import com.android.ide.eclipse.adt.internal.resources.IResourceRepository; import com.android.ide.eclipse.adt.internal.resources.ResourceItem; import com.android.ide.eclipse.adt.internal.resources.ResourceType; @@ -27,6 +26,7 @@ import com.android.ide.eclipse.adt.internal.resources.configurations.ResourceQua import com.android.ide.eclipse.adt.internal.resources.manager.files.IFolderWrapper; import com.android.layoutlib.api.IResourceValue; import com.android.layoutlib.utils.ResourceValue; +import com.android.sdklib.internal.io.IAbstractFolder; import org.eclipse.core.resources.IFolder; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceFile.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceFile.java index 75f002b..82f73f7 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceFile.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceFile.java @@ -16,10 +16,10 @@ package com.android.ide.eclipse.adt.internal.resources.manager; -import com.android.builders.IAbstractFile; import com.android.ide.eclipse.adt.internal.resources.ResourceType; import com.android.ide.eclipse.adt.internal.resources.configurations.FolderConfiguration; import com.android.layoutlib.api.IResourceValue; +import com.android.sdklib.internal.io.IAbstractFile; import java.util.Collection; @@ -27,15 +27,15 @@ import java.util.Collection; * Represents a Resource file (a file under $Project/res/) */ public abstract class ResourceFile extends Resource { - + private final IAbstractFile mFile; private final ResourceFolder mFolder; - + protected ResourceFile(IAbstractFile file, ResourceFolder folder) { mFile = file; mFolder = folder; } - + /* * (non-Javadoc) * @see com.android.ide.eclipse.editors.resources.manager.Resource#getConfiguration() @@ -44,21 +44,21 @@ public abstract class ResourceFile extends Resource { public FolderConfiguration getConfiguration() { return mFolder.getConfiguration(); } - + /** * Returns the IFile associated with the ResourceFile. */ public final IAbstractFile getFile() { return mFile; } - + /** * Returns the parent folder as a {@link ResourceFolder}. */ public final ResourceFolder getFolder() { return mFolder; } - + /** * Returns whether the resource is a framework resource. */ @@ -88,10 +88,10 @@ public abstract class ResourceFile extends Resource { */ public abstract Collection<ProjectResourceItem> getResources(ResourceType type, ProjectResources projectResources); - + /** * Returns the value of a resource generated by this file by {@link ResourceType} and name. - * <p/>If no resource match, <code>null</code> is returned. + * <p/>If no resource match, <code>null</code> is returned. * @param type the type of the resource. * @param name the name of the resource. */ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceFolder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceFolder.java index ae32300..7cb6605 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceFolder.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceFolder.java @@ -16,12 +16,12 @@ package com.android.ide.eclipse.adt.internal.resources.manager; -import com.android.builders.IAbstractFile; -import com.android.builders.IAbstractFolder; import com.android.ide.eclipse.adt.internal.resources.ResourceItem; import com.android.ide.eclipse.adt.internal.resources.ResourceType; import com.android.ide.eclipse.adt.internal.resources.configurations.FolderConfiguration; import com.android.ide.eclipse.adt.internal.resources.manager.files.IFileWrapper; +import com.android.sdklib.internal.io.IAbstractFile; +import com.android.sdklib.internal.io.IAbstractFolder; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; 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 162e163..6da34f4 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 @@ -16,10 +16,6 @@ package com.android.ide.eclipse.adt.internal.resources.manager; -import com.android.builders.FileWrapper; -import com.android.builders.FolderWrapper; -import com.android.builders.IAbstractFile; -import com.android.builders.IAbstractFolder; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.AndroidConstants; import com.android.ide.eclipse.adt.internal.resources.ResourceType; @@ -32,6 +28,10 @@ import com.android.ide.eclipse.adt.internal.resources.manager.files.IFileWrapper import com.android.ide.eclipse.adt.internal.resources.manager.files.IFolderWrapper; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.SdkConstants; +import com.android.sdklib.internal.io.FileWrapper; +import com.android.sdklib.internal.io.FolderWrapper; +import com.android.sdklib.internal.io.IAbstractFile; +import com.android.sdklib.internal.io.IAbstractFolder; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/SingleResourceFile.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/SingleResourceFile.java index 8e688f6..8af3f53 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/SingleResourceFile.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/SingleResourceFile.java @@ -16,12 +16,12 @@ package com.android.ide.eclipse.adt.internal.resources.manager; -import com.android.builders.IAbstractFile; import com.android.ide.eclipse.adt.internal.resources.ResourceType; import com.android.ide.eclipse.adt.internal.resources.configurations.PixelDensityQualifier; import com.android.layoutlib.api.IResourceValue; import com.android.layoutlib.utils.DensityBasedResourceValue; import com.android.layoutlib.utils.ResourceValue; +import com.android.sdklib.internal.io.IAbstractFile; import java.util.ArrayList; import java.util.Collection; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/files/IFileWrapper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/files/IFileWrapper.java index 27084c0..b8db6b0 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/files/IFileWrapper.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/files/IFileWrapper.java @@ -16,8 +16,8 @@ package com.android.ide.eclipse.adt.internal.resources.manager.files; -import com.android.builders.IAbstractFile; -import com.android.builders.StreamException; +import com.android.sdklib.internal.io.IAbstractFile; +import com.android.sdklib.internal.io.StreamException; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.CoreException; @@ -51,6 +51,10 @@ public class IFileWrapper implements IAbstractFile { return mFile.getName(); } + public boolean exists() { + return mFile.exists(); + } + /** * Returns the {@link IFile} object that the receiver could represent. Can be <code>null</code> */ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/files/IFolderWrapper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/files/IFolderWrapper.java index 4df4ccb..23dab60 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/files/IFolderWrapper.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/files/IFolderWrapper.java @@ -16,30 +16,45 @@ package com.android.ide.eclipse.adt.internal.resources.manager.files; -import com.android.builders.IAbstractFolder; +import com.android.sdklib.internal.io.IAbstractFile; +import com.android.sdklib.internal.io.IAbstractFolder; +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.Path; /** - * An implementation of {@link IAbstractFolder} on top of an {@link IFolder} object. + * An implementation of {@link IAbstractFolder} on top of either an {@link IFolder} or an + * {@link IContainer} object. */ public class IFolderWrapper implements IAbstractFolder { - private final IFolder mFolder; + private final IFolder mFolder; // could be null. + private final IContainer mContainer; // never null. public IFolderWrapper(IFolder folder) { - mFolder = folder; + mContainer = mFolder = folder; + } + + public IFolderWrapper(IContainer container) { + mFolder = container instanceof IFolder ? (IFolder)container : null; + mContainer = container; } public String getName() { - return mFolder.getName(); + return mContainer.getName(); + } + + public boolean exists() { + return mContainer.exists(); } public boolean hasFile(String name) { try { - IResource[] files = mFolder.members(); + IResource[] files = mContainer.members(); for (IResource file : files) { if (name.equals(file.getName())) { return true; @@ -52,6 +67,16 @@ public class IFolderWrapper implements IAbstractFolder { return false; } + public IAbstractFile getFile(String name) { + if (mFolder != null) { + IFile file = mFolder.getFile(name); + return new IFileWrapper(file); + } + + IFile file = mContainer.getFile(new Path(name)); + return new IFileWrapper(file); + } + /** * Returns the {@link IFolder} object that the receiver could represent. * Can be <code>null</code> @@ -75,6 +100,6 @@ public class IFolderWrapper implements IAbstractFolder { @Override public int hashCode() { - return mFolder.hashCode(); + return mContainer.hashCode(); } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java index ef1cfeb..e657329 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java @@ -21,6 +21,7 @@ import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.internal.project.AndroidClasspathContainerInitializer; import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; import com.android.ide.eclipse.adt.internal.project.ProjectState; +import com.android.ide.eclipse.adt.internal.project.ProjectState.LibraryState; import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor; import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor.IFileListener; import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor.IProjectListener; @@ -38,16 +39,23 @@ import com.android.sdklib.internal.project.ProjectProperties; import com.android.sdklib.internal.project.ProjectProperties.PropertyType; import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IMarkerDelta; +import org.eclipse.core.resources.IPathVariableManager; import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IncrementalProjectBuilder; +import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; @@ -71,6 +79,8 @@ import java.util.Map.Entry; * To get the list of platforms or add-ons present in the SDK, call {@link #getTargets()}. */ public class Sdk implements IProjectListener, IFileListener { + private final static Object sLock = new Object(); + private static Sdk sCurrentSdk = null; /** @@ -164,64 +174,76 @@ public class Sdk implements IProjectListener, IFileListener { } /** + * Returns the lock object used to synchronize all operations dealing with SDK, targets and + * projects. + */ + public static final Object getLock() { + return sLock; + } + + /** * Loads an SDK and returns an {@link Sdk} object if success. * <p/>If the SDK failed to load, it displays an error to the user. * @param sdkLocation the OS path to the SDK. */ - public static synchronized Sdk loadSdk(String sdkLocation) { - if (sCurrentSdk != null) { - sCurrentSdk.dispose(); - sCurrentSdk = null; - } + public static Sdk loadSdk(String sdkLocation) { + synchronized (sLock) { + if (sCurrentSdk != null) { + sCurrentSdk.dispose(); + sCurrentSdk = null; + } - final ArrayList<String> logMessages = new ArrayList<String>(); - ISdkLog log = new ISdkLog() { - public void error(Throwable throwable, String errorFormat, Object... arg) { - if (errorFormat != null) { - logMessages.add(String.format("Error: " + errorFormat, arg)); - } + final ArrayList<String> logMessages = new ArrayList<String>(); + ISdkLog log = new ISdkLog() { + public void error(Throwable throwable, String errorFormat, Object... arg) { + if (errorFormat != null) { + logMessages.add(String.format("Error: " + errorFormat, arg)); + } - if (throwable != null) { - logMessages.add(throwable.getMessage()); + if (throwable != null) { + logMessages.add(throwable.getMessage()); + } } - } - public void warning(String warningFormat, Object... arg) { - logMessages.add(String.format("Warning: " + warningFormat, arg)); - } + public void warning(String warningFormat, Object... arg) { + logMessages.add(String.format("Warning: " + warningFormat, arg)); + } - public void printf(String msgFormat, Object... arg) { - logMessages.add(String.format(msgFormat, arg)); - } - }; + public void printf(String msgFormat, Object... arg) { + logMessages.add(String.format(msgFormat, arg)); + } + }; - // get an SdkManager object for the location - SdkManager manager = SdkManager.createManager(sdkLocation, log); - if (manager != null) { - AvdManager avdManager = null; - try { - avdManager = new AvdManager(manager, log); - } catch (AndroidLocationException e) { - log.error(e, "Error parsing the AVDs"); - } - sCurrentSdk = new Sdk(manager, avdManager); - return sCurrentSdk; - } else { - StringBuilder sb = new StringBuilder("Error Loading the SDK:\n"); - for (String msg : logMessages) { - sb.append('\n'); - sb.append(msg); + // get an SdkManager object for the location + SdkManager manager = SdkManager.createManager(sdkLocation, log); + if (manager != null) { + AvdManager avdManager = null; + try { + avdManager = new AvdManager(manager, log); + } catch (AndroidLocationException e) { + log.error(e, "Error parsing the AVDs"); + } + sCurrentSdk = new Sdk(manager, avdManager); + return sCurrentSdk; + } else { + StringBuilder sb = new StringBuilder("Error Loading the SDK:\n"); + for (String msg : logMessages) { + sb.append('\n'); + sb.append(msg); + } + AdtPlugin.displayError("Android SDK", sb.toString()); } - AdtPlugin.displayError("Android SDK", sb.toString()); + return null; } - return null; } /** * Returns the current {@link Sdk} object. */ - public static synchronized Sdk getCurrent() { - return sCurrentSdk; + public static Sdk getCurrent() { + synchronized (sLock) { + return sCurrentSdk; + } } /** @@ -273,7 +295,7 @@ public class Sdk implements IProjectListener, IFileListener { } - synchronized (AdtPlugin.getDefault().getSdkLockObject()) { + synchronized (sLock) { boolean resolveProject = false; ProjectState state = getProject(project); @@ -355,7 +377,7 @@ public class Sdk implements IProjectListener, IFileListener { return null; } - synchronized (AdtPlugin.getDefault().getSdkLockObject()) { + synchronized (sLock) { ProjectState state = sProjectStateMap.get(project); if (state == null) { // load the default.properties from the project folder. @@ -376,9 +398,10 @@ public class Sdk implements IProjectListener, IFileListener { state = new ProjectState(project, properties); sProjectStateMap.put(project, state); - // load the ApkSettings as well. - ApkSettings apkSettings = ApkConfigurationHelper.getSettings(properties); - state.setApkSettings(apkSettings); + // try to resolve the target + if (AdtPlugin.getDefault().getSdkLoadStatus() == LoadStatus.LOADED) { + sCurrentSdk.loadTarget(state); + } } return state; @@ -402,6 +425,19 @@ public class Sdk implements IProjectListener, IFileListener { } /** + * Loads the {@link IAndroidTarget} for a given project. + * <p/>This method will get the target hash string from the project properties, and resolve + * it to an {@link IAndroidTarget} object and store it inside the {@link ProjectState}. + * @param state the state representing the project to load. + */ + public void loadTarget(ProjectState state) { + String hash = state.getTargetHashString(); + if (hash != null) { + state.setTarget(getTargetFromHashString(hash)); + } + } + + /** * Checks and loads (if needed) the data for a given target. * <p/> The data is loaded in a separate {@link Job}, and opened editors will be notified * through their implementation of {@link ITargetChangeListener#onTargetLoaded(IAndroidTarget)}. @@ -417,7 +453,7 @@ public class Sdk implements IProjectListener, IFileListener { public LoadStatus checkAndLoadTargetData(final IAndroidTarget target, IJavaProject project) { boolean loadData = false; - synchronized (AdtPlugin.getDefault().getSdkLockObject()) { + synchronized (sLock) { TargetLoadBundle bundle = mTargetDataStatusMap.get(target); if (bundle == null) { bundle = new TargetLoadBundle(); @@ -455,7 +491,7 @@ public class Sdk implements IProjectListener, IFileListener { IJavaProject[] javaProjectArray = null; - synchronized (plugin.getSdkLockObject()) { + synchronized (sLock) { TargetLoadBundle bundle = mTargetDataStatusMap.get(target); if (status.getCode() != IStatus.OK) { @@ -480,7 +516,7 @@ public class Sdk implements IProjectListener, IFileListener { return status; } catch (Throwable t) { - synchronized (plugin.getSdkLockObject()) { + synchronized (sLock) { TargetLoadBundle bundle = mTargetDataStatusMap.get(target); bundle.status = LoadStatus.FAILED; } @@ -507,7 +543,7 @@ public class Sdk implements IProjectListener, IFileListener { * Return the {@link AndroidTargetData} for a given {@link IAndroidTarget}. */ public AndroidTargetData getTargetData(IAndroidTarget target) { - synchronized (AdtPlugin.getDefault().getSdkLockObject()) { + synchronized (sLock) { return mTargetDataMap.get(target); } } @@ -516,7 +552,7 @@ public class Sdk implements IProjectListener, IFileListener { * Return the {@link AndroidTargetData} for a given {@link IProject}. */ public AndroidTargetData getTargetData(IProject project) { - synchronized (AdtPlugin.getDefault().getSdkLockObject()) { + synchronized (sLock) { IAndroidTarget target = getTarget(project); if (target != null) { return getTargetData(target); @@ -572,7 +608,7 @@ public class Sdk implements IProjectListener, IFileListener { loadLayoutDevices(); // update whatever ProjectState is already present with new IAndroidTarget objects. - synchronized (AdtPlugin.getDefault().getSdkLockObject()) { + synchronized (sLock) { for (Entry<IProject, ProjectState> entry: sProjectStateMap.entrySet()) { entry.getValue().setTarget( getTargetFromHashString(entry.getValue().getTargetHashString())); @@ -589,7 +625,7 @@ public class Sdk implements IProjectListener, IFileListener { monitor.removeFileListener(this); // the IAndroidTarget objects are now obsolete so update the project states. - synchronized (AdtPlugin.getDefault().getSdkLockObject()) { + synchronized (sLock) { for (Entry<IProject, ProjectState> entry: sProjectStateMap.entrySet()) { entry.getValue().setTarget(null); } @@ -597,7 +633,7 @@ public class Sdk implements IProjectListener, IFileListener { } void setTargetData(IAndroidTarget target, AndroidTargetData data) { - synchronized (AdtPlugin.getDefault().getSdkLockObject()) { + synchronized (sLock) { mTargetDataMap.put(target, data); } } @@ -659,7 +695,7 @@ public class Sdk implements IProjectListener, IFileListener { public void projectClosed(IProject project) { // get the target project - synchronized (AdtPlugin.getDefault().getSdkLockObject()) { + synchronized (sLock) { // direct access to the map since we're going to edit it. ProjectState state = sProjectStateMap.get(project); if (state != null) { @@ -685,14 +721,33 @@ public class Sdk implements IProjectListener, IFileListener { projectClosed(project); } - public void projectOpened(final IProject project) { - // ignore this. The project will be added to the map the first time the target needs - // to be resolved. + public void projectOpened(IProject openedProject) { + ProjectState openedState = getProject(openedProject); + if (openedState != null) { + // find dependencies, if any + if (openedState.isMissingLibraries()) { + // look for all opened projects to see if they are valid library for this project. + } + + // if the project is a library, then try to see if it's required by other projects. + if (openedState.isLibrary()) { + setupLibraryProject(openedProject); + + synchronized (sLock) { + for (ProjectState projectState : sProjectStateMap.values()) { + if (projectState != openedState && projectState.isMissingLibraries()) { + LibraryState libState = projectState.needs(openedProject); + if (libState != null) { + linkProjectAndLibrary(projectState, libState); + } + } + } + } + } + } } public void projectOpenedWithWorkspace(IProject project) { - // ignore this. The project will be added to the map the first time the target needs - // to be resolved. projectOpened(project); } @@ -723,5 +778,84 @@ public class Sdk implements IProjectListener, IFileListener { job.schedule(); } } + + private void setupLibraryProject(IProject libProject) { + // if needed add a path var for this library + IPathVariableManager pathVarMgr = + ResourcesPlugin.getWorkspace().getPathVariableManager(); + IPath libPath = libProject.getLocation(); + + final String libName = libProject.getName(); + final String varName = "_android_" + libName; //$NON-NLS-1$ + + if (libPath.equals(pathVarMgr.getValue(varName)) == false) { + try { + pathVarMgr.setValue(varName, libPath); + } catch (CoreException e) { + String message = String.format("Unable to set linked path var '%1$s' for library %2$s", + varName, libPath.toOSString()); + AdtPlugin.log(e, message); + } + } + } + + /** + * Links a project and a library so that the project can use the library code and resources. + * <p/>This is done in a job to be sure that the workspace is not locked for resource + * modification. + * @param projectState the {@link ProjectState} for the main project + * @param libraryState the {@link LibraryState} for the library project. + */ + private void linkProjectAndLibrary(final ProjectState projectState, + final LibraryState libraryState) { + Job job = new Job("Android Library link creation") { //$NON-NLS-1$ + @Override + protected IStatus run(IProgressMonitor monitor) { + try { + IProject project = projectState.getProject(); + IProject library = libraryState.getProject(); + + // add the library to the list of dynamic references + IProjectDescription projectDescription = project.getDescription(); + IProject[] refs = projectDescription.getDynamicReferences(); + if (refs.length > 0) { + IProject[] newrefs = new IProject[refs.length + 1]; + System.arraycopy(refs, 0, newrefs, 0, refs.length); + newrefs[refs.length] = library; + refs = newrefs; + } else { + refs = new IProject[] { library }; + } + projectDescription.setDynamicReferences(refs); + + // add a linked resource for the source of the library and add it to the project + final String libName = library.getName(); + final String varName = "_android_" + libName; //$NON-NLS-1$ + + // create a linked resource for the library using the path var. + IFolder libSrc = project.getFolder(libName); + // FIXME: make sure src has not been overriden? + String libSrcFolder = "src"; //$NON-NLS-1$ + libSrc.createLink(new Path(varName + "/" + libSrcFolder), //$NON-NLS-1$ + IResource.REPLACE, monitor); + + // use the folder as a source folder + IJavaProject javaProject = JavaCore.create(project); + IClasspathEntry[] entries = javaProject.getRawClasspath(); + + IClasspathEntry[] newEntries = new IClasspathEntry[entries.length + 1]; + System.arraycopy(entries, 0, newEntries, 0, entries.length); + newEntries[entries.length] = JavaCore.newSourceEntry(libSrc.getFullPath()); + javaProject.setRawClasspath(newEntries, monitor); + + return Status.OK_STATUS; + } catch (CoreException e) { + return e.getStatus(); + } + } + }; + job.setPriority(Job.BUILD); + job.schedule(); + } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ResourceExplorerView.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ResourceExplorerView.java index 77c67ef..ddf3f36 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ResourceExplorerView.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ResourceExplorerView.java @@ -16,7 +16,6 @@ package com.android.ide.eclipse.adt.internal.ui; -import com.android.builders.IAbstractFile; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.AndroidConstants; import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResourceItem; @@ -25,6 +24,7 @@ import com.android.ide.eclipse.adt.internal.resources.manager.ResourceFile; import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager; import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor.IResourceEventListener; import com.android.ide.eclipse.adt.internal.resources.manager.files.IFileWrapper; +import com.android.sdklib.internal.io.IAbstractFile; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectCreationPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectCreationPage.java index 733d60c..78346c1 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectCreationPage.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectCreationPage.java @@ -33,6 +33,7 @@ import com.android.sdklib.IAndroidTarget; import com.android.sdklib.SdkConstants; import com.android.sdklib.internal.project.ProjectProperties; import com.android.sdklib.internal.project.ProjectProperties.PropertyType; +import com.android.sdklib.xml.AndroidManifest; import com.android.sdkuilib.internal.widgets.SdkTargetSelector; import org.eclipse.core.filesystem.URIUtil; @@ -1052,7 +1053,7 @@ public class NewProjectCreationPage extends WizardPage { } if (activity != null) { - activityName = AndroidManifestParser.extractActivityName(activity.getName(), + activityName = AndroidManifest.extractActivityName(activity.getName(), packageName); } diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/.classpath b/eclipse/plugins/com.android.ide.eclipse.tests/.classpath index 17d578d..660adf3 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/.classpath +++ b/eclipse/plugins/com.android.ide.eclipse.tests/.classpath @@ -11,6 +11,5 @@ <classpathentry kind="lib" path="layoutlib.jar"/> <classpathentry kind="lib" path="kxml2-2.3.0.jar"/> <classpathentry kind="lib" path="groovy-all-1.7.0.jar"/> - <classpathentry kind="lib" path="/adt/builders.jar"/> <classpathentry kind="output" path="bin"/> </classpath> diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/tests/SdkTestCase.java b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/tests/SdkTestCase.java index d3210eb..9862ba2 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/tests/SdkTestCase.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/tests/SdkTestCase.java @@ -60,7 +60,7 @@ public abstract class SdkTestCase extends TestCase { return null; } - Object sdkLock = adt.getSdkLockObject(); + Object sdkLock = Sdk.getLock(); LoadStatus loadStatus = LoadStatus.LOADING; // wait for ADT to load the SDK on a separate thread // loop max of 600 times * 200 ms = 2 minutes diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/resources/manager/ConfigMatchTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/resources/manager/ConfigMatchTest.java index e81e70e..a09b82f 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/resources/manager/ConfigMatchTest.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/resources/manager/ConfigMatchTest.java @@ -16,7 +16,6 @@ package com.android.ide.eclipse.adt.internal.editors.resources.manager; -import com.android.builders.IAbstractFolder; import com.android.ide.eclipse.adt.internal.resources.configurations.FolderConfiguration; import com.android.ide.eclipse.adt.internal.resources.configurations.ResourceQualifier; import com.android.ide.eclipse.adt.internal.resources.configurations.KeyboardStateQualifier.KeyboardState; @@ -35,6 +34,7 @@ import com.android.ide.eclipse.adt.internal.resources.manager.files.IFolderWrapp import com.android.ide.eclipse.mock.FileMock; import com.android.ide.eclipse.mock.FolderMock; import com.android.sdklib.IAndroidTarget; +import com.android.sdklib.internal.io.IAbstractFolder; import java.lang.reflect.Field; import java.lang.reflect.Method; diff --git a/eclipse/scripts/create_adt_symlinks.sh b/eclipse/scripts/create_adt_symlinks.sh index 95f0325..46d0d33 100755 --- a/eclipse/scripts/create_adt_symlinks.sh +++ b/eclipse/scripts/create_adt_symlinks.sh @@ -14,7 +14,7 @@ DEST="sdk/eclipse/plugins/com.android.ide.eclipse.adt" # computes "../.." from DEST to here (in /android) BACK=`echo $DEST | sed 's@[^/]*@..@g'` -LIBS="sdkstats jarutils androidprefs layoutlib_api layoutlib_utils ninepatch sdklib sdkuilib builders" +LIBS="sdkstats jarutils androidprefs layoutlib_api layoutlib_utils ninepatch sdklib sdkuilib" echo "make java libs ..." make -j3 showcommands $LIBS || die "ADT: Fail to build one of $LIBS." |