aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/ResourceManagerBuilder.java
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/ResourceManagerBuilder.java')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/ResourceManagerBuilder.java317
1 files changed, 317 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/ResourceManagerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/ResourceManagerBuilder.java
new file mode 100644
index 000000000..8e01cca29
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/ResourceManagerBuilder.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.eclipse.adt.internal.build.builders;
+
+import com.android.SdkConstants;
+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.preferences.AdtPrefs;
+import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity;
+import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
+import com.android.ide.eclipse.adt.internal.project.ProjectHelper;
+import com.android.ide.eclipse.adt.internal.sdk.ProjectState;
+import com.android.ide.eclipse.adt.internal.sdk.Sdk;
+import com.android.sdklib.BuildToolInfo;
+import com.android.sdklib.IAndroidTarget;
+import com.android.utils.Pair;
+
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRoot;
+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.Status;
+import org.eclipse.core.runtime.SubProgressMonitor;
+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;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Resource manager builder whose only purpose is to refresh the resource folder
+ * so that the other builder use an up to date version.
+ */
+public class ResourceManagerBuilder extends BaseBuilder {
+
+ public static final String ID = "com.android.ide.eclipse.adt.ResourceManagerBuilder"; //$NON-NLS-1$
+
+ public ResourceManagerBuilder() {
+ super();
+ }
+
+ @Override
+ protected void clean(IProgressMonitor monitor) throws CoreException {
+ super.clean(monitor);
+
+ // Get the project.
+ IProject project = getProject();
+
+ // Clear the project of the generic markers
+ removeMarkersFromContainer(project, AdtConstants.MARKER_ADT);
+ }
+
+ // build() returns a list of project from which this project depends for future compilation.
+ @SuppressWarnings("unchecked")
+ @Override
+ protected IProject[] build(int kind, Map args, IProgressMonitor monitor)
+ throws CoreException {
+ // Get the project.
+ final IProject project = getProject();
+ IJavaProject javaProject = JavaCore.create(project);
+
+ // Clear the project of the generic markers
+ removeMarkersFromContainer(project, AdtConstants.MARKER_ADT);
+
+ // check for existing target marker, in which case we abort.
+ // (this means: no SDK, no target, or unresolvable target.)
+ try {
+ abortOnBadSetup(javaProject, null);
+ } catch (AbortBuildException e) {
+ return null;
+ }
+
+ // Check the compiler compliance level, displaying the error message
+ // since this is the first builder.
+ Pair<Integer, String> result = ProjectHelper.checkCompilerCompliance(project);
+ String errorMessage = null;
+ switch (result.getFirst().intValue()) {
+ case ProjectHelper.COMPILER_COMPLIANCE_LEVEL:
+ errorMessage = Messages.Requires_Compiler_Compliance_s;
+ break;
+ case ProjectHelper.COMPILER_COMPLIANCE_SOURCE:
+ errorMessage = Messages.Requires_Source_Compatibility_s;
+ break;
+ case ProjectHelper.COMPILER_COMPLIANCE_CODEGEN_TARGET:
+ errorMessage = Messages.Requires_Class_Compatibility_s;
+ break;
+ }
+
+ if (errorMessage != null) {
+ errorMessage = String.format(errorMessage,
+ result.getSecond() == null ? "(no value)" : result.getSecond());
+
+ if (JavaCore.VERSION_1_7.equals(result.getSecond())) {
+ // If the user is trying to target 1.7 but compiling with something older,
+ // the error message can be a bit misleading; instead point them in the
+ // direction of updating the project's build target.
+ Sdk currentSdk = Sdk.getCurrent();
+ if (currentSdk != null) {
+ IAndroidTarget target = currentSdk.getTarget(project.getProject());
+ if (target != null && target.getVersion().getApiLevel() < 19) {
+ errorMessage = "Using 1.7 requires compiling with Android 4.4 " +
+ "(KitKat); currently using " + target.getVersion();
+ }
+
+ ProjectState projectState = Sdk.getProjectState(project);
+ if (projectState != null) {
+ BuildToolInfo buildToolInfo = projectState.getBuildToolInfo();
+ if (buildToolInfo == null) {
+ buildToolInfo = currentSdk.getLatestBuildTool();
+ }
+ if (buildToolInfo != null && buildToolInfo.getRevision().getMajor() < 19) {
+ errorMessage = "Using 1.7 requires using Android Build Tools " +
+ "version 19 or later; currently using " +
+ buildToolInfo.getRevision();
+ }
+ }
+ }
+ }
+
+ markProject(AdtConstants.MARKER_ADT, errorMessage, IMarker.SEVERITY_ERROR);
+ AdtPlugin.printErrorToConsole(project, errorMessage);
+
+ return null;
+ }
+
+ // Check that the SDK directory has been setup.
+ String osSdkFolder = AdtPlugin.getOsSdkFolder();
+
+ if (osSdkFolder == null || osSdkFolder.length() == 0) {
+ AdtPlugin.printErrorToConsole(project, Messages.No_SDK_Setup_Error);
+ markProject(AdtConstants.MARKER_ADT, Messages.No_SDK_Setup_Error,
+ IMarker.SEVERITY_ERROR);
+
+ return null;
+ }
+
+ // check the 'gen' source folder is present
+ boolean hasGenSrcFolder = false; // whether the project has a 'gen' source folder setup
+
+ IClasspathEntry[] classpaths = javaProject.readRawClasspath();
+ if (classpaths != null) {
+ for (IClasspathEntry e : classpaths) {
+ if (e.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
+ IPath path = e.getPath();
+ if (path.segmentCount() == 2 &&
+ path.segment(1).equals(SdkConstants.FD_GEN_SOURCES)) {
+ hasGenSrcFolder = true;
+ break;
+ }
+ }
+ }
+ }
+
+ boolean genFolderPresent = false; // whether the gen folder actually exists
+ IResource resource = project.findMember(SdkConstants.FD_GEN_SOURCES);
+ genFolderPresent = resource != null && resource.exists();
+
+ if (hasGenSrcFolder == false && genFolderPresent) {
+ // No source folder setup for 'gen' in the project, but there's already a
+ // 'gen' resource (file or folder).
+ String message;
+ if (resource.getType() == IResource.FOLDER) {
+ // folder exists already! This is an error. If the folder had been created
+ // by the NewProjectWizard, it'd be a source folder.
+ message = String.format("%1$s already exists but is not a source folder. Convert to a source folder or rename it.",
+ resource.getFullPath().toString());
+ } else {
+ // resource exists but is not a folder.
+ message = String.format(
+ "Resource %1$s is in the way. ADT needs a source folder called 'gen' to work. Rename or delete resource.",
+ resource.getFullPath().toString());
+ }
+
+ AdtPlugin.printErrorToConsole(project, message);
+ markProject(AdtConstants.MARKER_ADT, message, IMarker.SEVERITY_ERROR);
+
+ return null;
+ } else if (hasGenSrcFolder == false || genFolderPresent == false) {
+ // either there is no 'gen' source folder in the project (older SDK),
+ // or the folder does not exist (was deleted, or was a fresh svn checkout maybe.)
+
+ // In case we are migrating from an older SDK, we go through the current source
+ // folders and delete the generated Java files.
+ List<IPath> sourceFolders = BaseProjectHelper.getSourceClasspaths(javaProject);
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ for (IPath path : sourceFolders) {
+ IResource member = root.findMember(path);
+ if (member != null) {
+ removeDerivedResources(member, monitor);
+ }
+ }
+
+ // create the new source folder, if needed
+ IFolder genFolder = project.getFolder(SdkConstants.FD_GEN_SOURCES);
+ if (genFolderPresent == false) {
+ AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project,
+ "Creating 'gen' source folder for generated Java files");
+ genFolder.create(true /* force */, true /* local */,
+ new SubProgressMonitor(monitor, 10));
+ }
+
+ // add it to the source folder list, if needed only (or it will throw)
+ if (hasGenSrcFolder == false) {
+ IClasspathEntry[] entries = javaProject.getRawClasspath();
+ entries = ProjectHelper.addEntryToClasspath(entries,
+ JavaCore.newSourceEntry(genFolder.getFullPath()));
+ javaProject.setRawClasspath(entries, new SubProgressMonitor(monitor, 10));
+ }
+
+ // refresh specifically the gen folder first, as it may break the build
+ // if it doesn't arrive in time then refresh the whole project as usual.
+ genFolder.refreshLocal(IResource.DEPTH_ZERO, new SubProgressMonitor(monitor, 10));
+ project.refreshLocal(IResource.DEPTH_INFINITE, new SubProgressMonitor(monitor, 10));
+
+ // it seems like doing this fails to properly rebuild the project. the Java builder
+ // running right after this builder will not see the gen folder, and will not be
+ // restarted after this build. Therefore in this particular case, we start another
+ // build asynchronously so that it's rebuilt after this build.
+ launchJob(new Job("rebuild") {
+ @Override
+ protected IStatus run(IProgressMonitor m) {
+ try {
+ project.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, m);
+ return Status.OK_STATUS;
+ } catch (CoreException e) {
+ return e.getStatus();
+ }
+ }
+ });
+
+ }
+
+ // convert older projects which use bin as the eclipse output folder into projects
+ // using bin/classes
+ IFolder androidOutput = BaseProjectHelper.getAndroidOutputFolder(project);
+ IFolder javaOutput = BaseProjectHelper.getJavaOutputFolder(project);
+ if (androidOutput.exists() == false || javaOutput == null ||
+ javaOutput.getParent().equals(androidOutput) == false) {
+ // get what we want as the new java output.
+ IFolder newJavaOutput = androidOutput.getFolder(SdkConstants.FD_CLASSES_OUTPUT);
+
+ if (androidOutput.exists() == false) {
+ androidOutput.create(true /*force*/, true /*local*/, monitor);
+ }
+
+ if (newJavaOutput.exists() == false) {
+ newJavaOutput.create(true /*force*/, true /*local*/, monitor);
+ }
+
+ // set the java output to this project.
+ javaProject.setOutputLocation(newJavaOutput.getFullPath(), monitor);
+
+ // need to do a full build. Can't build while we're already building, so launch a
+ // job to build it right after this build
+ launchJob(new Job("rebuild") {
+ @Override
+ protected IStatus run(IProgressMonitor jobMonitor) {
+ try {
+ project.build(IncrementalProjectBuilder.CLEAN_BUILD, jobMonitor);
+ return Status.OK_STATUS;
+ } catch (CoreException e) {
+ return e.getStatus();
+ }
+ }
+ });
+ }
+
+ // check that we have bin/res/
+ IFolder binResFolder = androidOutput.getFolder(SdkConstants.FD_RESOURCES);
+ if (binResFolder.exists() == false) {
+ binResFolder.create(true /* force */, true /* local */,
+ new SubProgressMonitor(monitor, 10));
+ project.refreshLocal(IResource.DEPTH_ONE, new SubProgressMonitor(monitor, 10));
+ }
+
+ // Check the preference to be sure we are supposed to refresh
+ // the folders.
+ if (AdtPrefs.getPrefs().getBuildForceResResfresh()) {
+ AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, Messages.Refreshing_Res);
+
+ // refresh the res folder.
+ IFolder resFolder = project.getFolder(AdtConstants.WS_RESOURCES);
+ resFolder.refreshLocal(IResource.DEPTH_INFINITE, monitor);
+
+ // Also refresh the assets folder to make sure the ApkBuilder
+ // will now it's changed and will force a new resource packaging.
+ IFolder assetsFolder = project.getFolder(AdtConstants.WS_ASSETS);
+ assetsFolder.refreshLocal(IResource.DEPTH_INFINITE, monitor);
+ }
+
+ return null;
+ }
+}