diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project')
17 files changed, 0 insertions, 5760 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidClasspathContainer.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidClasspathContainer.java deleted file mode 100644 index 475dd5a44..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidClasspathContainer.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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.project; - -import org.eclipse.core.runtime.IPath; -import org.eclipse.jdt.core.IClasspathContainer; -import org.eclipse.jdt.core.IClasspathEntry; - -/** - * Classpath container for the Android projects. - * This supports both the System classpath and the library dependencies. - */ -class AndroidClasspathContainer implements IClasspathContainer { - - private final IClasspathEntry[] mClasspathEntry; - private final IPath mContainerPath; - private final String mName; - private final int mKind; - - /** - * Constructs the container with the {@link IClasspathEntry} representing the android - * framework jar file and the container id - * @param entries the entries representing the android framework and optional libraries. - * @param path the path containing the classpath container id. - * @param name the name of the container to display. - * @param the container kind. Can be {@link IClasspathContainer#K_DEFAULT_SYSTEM} or - * {@link IClasspathContainer#K_APPLICATION} - */ - AndroidClasspathContainer(IClasspathEntry[] entries, IPath path, String name, int kind) { - mClasspathEntry = entries; - mContainerPath = path; - mName = name; - mKind = kind; - } - - @Override - public IClasspathEntry[] getClasspathEntries() { - return mClasspathEntry; - } - - @Override - public String getDescription() { - return mName; - } - - @Override - public int getKind() { - return mKind; - } - - @Override - public IPath getPath() { - return mContainerPath; - } -} 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 deleted file mode 100644 index f9382c5ae..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidClasspathContainerInitializer.java +++ /dev/null @@ -1,823 +0,0 @@ -/* - * 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.project; - -import com.android.SdkConstants; -import com.android.ide.common.sdk.LoadStatus; -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.sdk.ProjectState; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; -import com.android.sdklib.AndroidVersion; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.IAndroidTarget.IOptionalLibrary; -import com.google.common.collect.Maps; -import com.google.common.io.Closeables; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.FileLocator; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.Platform; -import org.eclipse.jdt.core.IAccessRule; -import org.eclipse.jdt.core.IClasspathAttribute; -import org.eclipse.jdt.core.IClasspathContainer; -import org.eclipse.jdt.core.IClasspathEntry; -import org.eclipse.jdt.core.IJavaModel; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.JavaModelException; -import org.osgi.framework.Bundle; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLConnection; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Map; -import java.util.regex.Pattern; - -/** - * Classpath container initializer responsible for binding {@link AndroidClasspathContainer} to - * {@link IProject}s. This removes the hard-coded path to the android.jar. - */ -public class AndroidClasspathContainerInitializer extends BaseClasspathContainerInitializer { - - public static final String NULL_API_URL = "<null>"; //$NON-NLS-1$ - - public static final String SOURCES_ZIP = "/sources.zip"; //$NON-NLS-1$ - - public static final String COM_ANDROID_IDE_ECLIPSE_ADT_SOURCE = - "com.android.ide.eclipse.source"; //$NON-NLS-1$ - - private static final String ANDROID_API_REFERENCE = - "http://developer.android.com/reference/"; //$NON-NLS-1$ - - private final static String PROPERTY_ANDROID_API = "androidApi"; //$NON-NLS-1$ - - private final static String PROPERTY_ANDROID_SOURCE = "androidSource"; //$NON-NLS-1$ - - /** path separator to store multiple paths in a single property. This is guaranteed to not - * be in a path. - */ - private final static String PATH_SEPARATOR = "\u001C"; //$NON-NLS-1$ - - private final static String PROPERTY_CONTAINER_CACHE = "androidContainerCache"; //$NON-NLS-1$ - private final static String PROPERTY_TARGET_NAME = "androidTargetCache"; //$NON-NLS-1$ - private final static String CACHE_VERSION = "01"; //$NON-NLS-1$ - private final static String CACHE_VERSION_SEP = CACHE_VERSION + PATH_SEPARATOR; - - private final static int CACHE_INDEX_JAR = 0; - private final static int CACHE_INDEX_SRC = 1; - private final static int CACHE_INDEX_DOCS_URI = 2; - private final static int CACHE_INDEX_OPT_DOCS_URI = 3; - private final static int CACHE_INDEX_ADD_ON_START = CACHE_INDEX_OPT_DOCS_URI; - - public AndroidClasspathContainerInitializer() { - // pass - } - - /** - * Binds a classpath container to a {@link IClasspathContainer} for a given project, - * or silently fails if unable to do so. - * @param containerPath the container path that is the container id. - * @param project the project to bind - */ - @Override - public void initialize(IPath containerPath, IJavaProject project) throws CoreException { - if (AdtConstants.CONTAINER_FRAMEWORK.equals(containerPath.toString())) { - IClasspathContainer container = allocateAndroidContainer(project); - if (container != null) { - JavaCore.setClasspathContainer(new Path(AdtConstants.CONTAINER_FRAMEWORK), - new IJavaProject[] { project }, - new IClasspathContainer[] { container }, - new NullProgressMonitor()); - } - } - } - - /** - * Updates the {@link IJavaProject} objects with new android framework container. This forces - * JDT to recompile them. - * @param androidProjects the projects to update. - * @return <code>true</code> if success, <code>false</code> otherwise. - */ - static boolean updateProjects(IJavaProject[] androidProjects) { - try { - // Allocate a new AndroidClasspathContainer, and associate it to the android framework - // container id for each projects. - // By providing a new association between a container id and a IClasspathContainer, - // this forces the JDT to query the IClasspathContainer for new IClasspathEntry (with - // IClasspathContainer#getClasspathEntries()), and therefore force recompilation of - // the projects. - int projectCount = androidProjects.length; - - IClasspathContainer[] containers = new IClasspathContainer[projectCount]; - for (int i = 0 ; i < projectCount; i++) { - containers[i] = allocateAndroidContainer(androidProjects[i]); - } - - // give each project their new container in one call. - JavaCore.setClasspathContainer( - new Path(AdtConstants.CONTAINER_FRAMEWORK), - androidProjects, containers, new NullProgressMonitor()); - - return true; - } catch (JavaModelException e) { - return false; - } - } - - /** - * Allocates and returns an {@link AndroidClasspathContainer} object with the proper - * path to the framework jar file. - * @param javaProject The java project that will receive the container. - */ - private static IClasspathContainer allocateAndroidContainer(IJavaProject javaProject) { - final IProject iProject = javaProject.getProject(); - - String markerMessage = null; - boolean outputToConsole = true; - IAndroidTarget target = null; - - try { - AdtPlugin plugin = AdtPlugin.getDefault(); - if (plugin == null) { // This is totally weird, but I've seen it happen! - return null; - } - - synchronized (Sdk.getLock()) { - boolean sdkIsLoaded = plugin.getSdkLoadStatus() == LoadStatus.LOADED; - - // check if the project has a valid target. - ProjectState state = Sdk.getProjectState(iProject); - if (state == null) { - // looks like the project state (project.properties) couldn't be read! - markerMessage = String.format( - "Project has no %1$s file! Edit the project properties to set one.", - SdkConstants.FN_PROJECT_PROPERTIES); - } else { - // this might be null if the sdk is not yet loaded. - target = state.getTarget(); - - // if we are loaded and the target is non null, we create a valid - // ClassPathContainer - if (sdkIsLoaded && target != null) { - // check the renderscript support mode. If support mode is enabled, - // target API must be 18+ - if (!state.getRenderScriptSupportMode() || - target.getVersion().getApiLevel() >= 18) { - // first make sure the target has loaded its data - Sdk.getCurrent().checkAndLoadTargetData(target, null /*project*/); - - String targetName = target.getClasspathName(); - - return new AndroidClasspathContainer( - createClasspathEntries(iProject, target, targetName), - new Path(AdtConstants.CONTAINER_FRAMEWORK), - targetName, - IClasspathContainer.K_DEFAULT_SYSTEM); - } else { - markerMessage = "Renderscript support mode requires compilation target API to be 18+."; - } - } else { - // In case of error, we'll try different thing to provide the best error message - // possible. - // Get the project's target's hash string (if it exists) - String hashString = state.getTargetHashString(); - - if (hashString == null || hashString.length() == 0) { - // if there is no hash string we only show this if the SDK is loaded. - // For a project opened at start-up with no target, this would be displayed - // twice, once when the project is opened, and once after the SDK has - // finished loading. - // By testing the sdk is loaded, we only show this once in the console. - if (sdkIsLoaded) { - markerMessage = String.format( - "Project has no target set. Edit the project properties to set one."); - } - } else if (sdkIsLoaded) { - markerMessage = String.format( - "Unable to resolve target '%s'", hashString); - } else { - // this is the case where there is a hashString but the SDK is not yet - // loaded and therefore we can't get the target yet. - // We check if there is a cache of the needed information. - AndroidClasspathContainer container = getContainerFromCache(iProject, - target); - - if (container == null) { - // either the cache was wrong (ie folder does not exists anymore), or - // there was no cache. In this case we need to make sure the project - // is resolved again after the SDK is loaded. - plugin.setProjectToResolve(javaProject); - - markerMessage = String.format( - "Unable to resolve target '%s' until the SDK is loaded.", - hashString); - - // let's not log this one to the console as it will happen at - // every boot, and it's expected. (we do keep the error marker though). - outputToConsole = false; - - } else { - // we created a container from the cache, so we register the project - // to be checked for cache validity once the SDK is loaded - plugin.setProjectToCheck(javaProject); - - // and return the container - return container; - } - } - } - } - - // return a dummy container to replace the one we may have had before. - // It'll be replaced by the real when if/when the target is resolved if/when the - // SDK finishes loading. - return new IClasspathContainer() { - @Override - public IClasspathEntry[] getClasspathEntries() { - return new IClasspathEntry[0]; - } - - @Override - public String getDescription() { - return "Unable to get system library for the project"; - } - - @Override - public int getKind() { - return IClasspathContainer.K_DEFAULT_SYSTEM; - } - - @Override - public IPath getPath() { - return null; - } - }; - } - } finally { - processError(iProject, markerMessage, AdtConstants.MARKER_TARGET, outputToConsole); - } - } - - /** - * Creates and returns an array of {@link IClasspathEntry} objects for the android - * framework and optional libraries. - * <p/>This references the OS path to the android.jar and the - * java doc directory. This is dynamically created when a project is opened, - * and never saved in the project itself, so there's no risk of storing an - * obsolete path. - * The method also stores the paths used to create the entries in the project persistent - * properties. A new {@link AndroidClasspathContainer} can be created from the stored path - * using the {@link #getContainerFromCache(IProject)} method. - * @param project - * @param target The target that contains the libraries. - * @param targetName - */ - private static IClasspathEntry[] createClasspathEntries(IProject project, - IAndroidTarget target, String targetName) { - - // get the path from the target - String[] paths = getTargetPaths(target); - - // create the classpath entry from the paths - IClasspathEntry[] entries = createClasspathEntriesFromPaths(paths, target); - - // paths now contains all the path required to recreate the IClasspathEntry with no - // target info. We encode them in a single string, with each path separated by - // OS path separator. - StringBuilder sb = new StringBuilder(CACHE_VERSION); - for (String p : paths) { - sb.append(PATH_SEPARATOR); - sb.append(p); - } - - // store this in a project persistent property - ProjectHelper.saveStringProperty(project, PROPERTY_CONTAINER_CACHE, sb.toString()); - ProjectHelper.saveStringProperty(project, PROPERTY_TARGET_NAME, targetName); - - return entries; - } - - /** - * Generates an {@link AndroidClasspathContainer} from the project cache, if possible. - */ - private static AndroidClasspathContainer getContainerFromCache(IProject project, - IAndroidTarget target) { - // get the cached info from the project persistent properties. - String cache = ProjectHelper.loadStringProperty(project, PROPERTY_CONTAINER_CACHE); - String targetNameCache = ProjectHelper.loadStringProperty(project, PROPERTY_TARGET_NAME); - if (cache == null || targetNameCache == null) { - return null; - } - - // the first 2 chars must match CACHE_VERSION. The 3rd char is the normal separator. - if (cache.startsWith(CACHE_VERSION_SEP) == false) { - return null; - } - - cache = cache.substring(CACHE_VERSION_SEP.length()); - - // the cache contains multiple paths, separated by a character guaranteed to not be in - // the path (\u001C). - // The first 3 are for android.jar (jar, source, doc), the rest are for the optional - // libraries and should contain at least one doc and a jar (if there are any libraries). - // Therefore, the path count should be 3 or 5+ - String[] paths = cache.split(Pattern.quote(PATH_SEPARATOR)); - if (paths.length < 3 || paths.length == 4) { - return null; - } - - // now we check the paths actually exist. - // There's an exception: If the source folder for android.jar does not exist, this is - // not a problem, so we skip it. - // Also paths[CACHE_INDEX_DOCS_URI] is a URI to the javadoc, so we test it a - // bit differently. - try { - if (new File(paths[CACHE_INDEX_JAR]).exists() == false || - new File(new URI(paths[CACHE_INDEX_DOCS_URI])).exists() == false) { - return null; - } - - // check the path for the add-ons, if they exist. - if (paths.length > CACHE_INDEX_ADD_ON_START) { - - // check the docs path separately from the rest of the paths as it's a URI. - if (new File(new URI(paths[CACHE_INDEX_OPT_DOCS_URI])).exists() == false) { - return null; - } - - // now just check the remaining paths. - for (int i = CACHE_INDEX_ADD_ON_START + 1; i < paths.length; i++) { - String path = paths[i]; - if (path.length() > 0) { - File f = new File(path); - if (f.exists() == false) { - return null; - } - } - } - } - } catch (URISyntaxException e) { - return null; - } - - IClasspathEntry[] entries = createClasspathEntriesFromPaths(paths, target); - - return new AndroidClasspathContainer(entries, - new Path(AdtConstants.CONTAINER_FRAMEWORK), - targetNameCache, IClasspathContainer.K_DEFAULT_SYSTEM); - } - - /** - * Generates an array of {@link IClasspathEntry} from a set of paths. - * @see #getTargetPaths(IAndroidTarget) - */ - private static IClasspathEntry[] createClasspathEntriesFromPaths(String[] paths, - IAndroidTarget target) { - ArrayList<IClasspathEntry> list = new ArrayList<IClasspathEntry>(); - - // First, we create the IClasspathEntry for the framework. - // now add the android framework to the class path. - // create the path object. - IPath androidLib = new Path(paths[CACHE_INDEX_JAR]); - - IPath androidSrc = null; - String androidSrcOsPath = null; - IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); - if (target != null) { - androidSrcOsPath = - ProjectHelper.loadStringProperty(root, getAndroidSourceProperty(target)); - } - if (androidSrcOsPath != null && androidSrcOsPath.trim().length() > 0) { - androidSrc = new Path(androidSrcOsPath); - } - if (androidSrc == null) { - androidSrc = new Path(paths[CACHE_INDEX_SRC]); - File androidSrcFile = new File(paths[CACHE_INDEX_SRC]); - if (!androidSrcFile.isDirectory()) { - androidSrc = null; - } - } - - if (androidSrc == null && target != null) { - Bundle bundle = getSourceBundle(); - - if (bundle != null) { - AndroidVersion version = target.getVersion(); - String apiString = version.getApiString(); - String sourcePath = apiString + SOURCES_ZIP; - URL sourceURL = bundle.getEntry(sourcePath); - if (sourceURL != null) { - URL url = null; - try { - url = FileLocator.resolve(sourceURL); - } catch (IOException ignore) { - } - if (url != null) { - androidSrcOsPath = url.getFile(); - if (new File(androidSrcOsPath).isFile()) { - androidSrc = new Path(androidSrcOsPath); - } - } - } - } - } - - // create the java doc link. - String androidApiURL = ProjectHelper.loadStringProperty(root, PROPERTY_ANDROID_API); - String apiURL = null; - if (androidApiURL != null && testURL(androidApiURL)) { - apiURL = androidApiURL; - } else { - if (testURL(paths[CACHE_INDEX_DOCS_URI])) { - apiURL = paths[CACHE_INDEX_DOCS_URI]; - } else if (testURL(ANDROID_API_REFERENCE)) { - apiURL = ANDROID_API_REFERENCE; - } - } - - IClasspathAttribute[] attributes = null; - if (apiURL != null && !NULL_API_URL.equals(apiURL)) { - IClasspathAttribute cpAttribute = JavaCore.newClasspathAttribute( - IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME, apiURL); - attributes = new IClasspathAttribute[] { - cpAttribute - }; - } - // create the access rule to restrict access to classes in - // com.android.internal - IAccessRule accessRule = JavaCore.newAccessRule(new Path("com/android/internal/**"), //$NON-NLS-1$ - IAccessRule.K_NON_ACCESSIBLE); - - IClasspathEntry frameworkClasspathEntry = JavaCore.newLibraryEntry(androidLib, - androidSrc, // source attachment path - null, // default source attachment root path. - new IAccessRule[] { accessRule }, - attributes, - false // not exported. - ); - - list.add(frameworkClasspathEntry); - - // now deal with optional libraries - if (paths.length >= 5) { - String docPath = paths[CACHE_INDEX_OPT_DOCS_URI]; - int i = 4; - while (i < paths.length) { - Path jarPath = new Path(paths[i++]); - - attributes = null; - if (docPath.length() > 0) { - attributes = new IClasspathAttribute[] { - JavaCore.newClasspathAttribute( - IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME, docPath) - }; - } - - IClasspathEntry entry = JavaCore.newLibraryEntry( - jarPath, - null, // source attachment path - null, // default source attachment root path. - null, - attributes, - false // not exported. - ); - list.add(entry); - } - } - - if (apiURL != null) { - ProjectHelper.saveStringProperty(root, PROPERTY_ANDROID_API, apiURL); - } - if (androidSrc != null && target != null) { - ProjectHelper.saveStringProperty(root, getAndroidSourceProperty(target), - androidSrc.toOSString()); - } - return list.toArray(new IClasspathEntry[list.size()]); - } - - private static Bundle getSourceBundle() { - String bundleId = System.getProperty(COM_ANDROID_IDE_ECLIPSE_ADT_SOURCE, - COM_ANDROID_IDE_ECLIPSE_ADT_SOURCE); - Bundle bundle = Platform.getBundle(bundleId); - return bundle; - } - - private static String getAndroidSourceProperty(IAndroidTarget target) { - if (target == null) { - return null; - } - String androidSourceProperty = PROPERTY_ANDROID_SOURCE + "_" - + target.getVersion().getApiString(); - return androidSourceProperty; - } - - /** - * Cache results for testURL: Some are expensive to compute, and this is - * called repeatedly (perhaps for each open project) - */ - private static final Map<String, Boolean> sRecentUrlValidCache = - Maps.newHashMapWithExpectedSize(4); - - @SuppressWarnings("resource") // Eclipse does not handle Closeables#closeQuietly - private static boolean testURL(String androidApiURL) { - Boolean cached = sRecentUrlValidCache.get(androidApiURL); - if (cached != null) { - return cached.booleanValue(); - } - boolean valid = false; - InputStream is = null; - try { - URL testURL = new URL(androidApiURL); - URLConnection connection = testURL.openConnection(); - // Only try for 5 seconds (though some implementations ignore this flag) - connection.setConnectTimeout(5000); - connection.setReadTimeout(5000); - is = connection.getInputStream(); - valid = true; - } catch (Exception ignore) { - } finally { - Closeables.closeQuietly(is); - } - - sRecentUrlValidCache.put(androidApiURL, valid); - - return valid; - } - - /** - * Checks the projects' caches. If the cache was valid, the project is removed from the list. - * @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); - IProject iProject = javaProject.getProject(); - - // check if the project is opened - if (iProject.isOpen() == false) { - // remove from the list - // we do not increment i in this case. - projects.remove(i); - - 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. - IAndroidTarget target = currentSdk.loadTargetAndBuildTools( - Sdk.getProjectState(iProject)); - if (target == null) { - // this is really not supposed to happen. This would mean there are cached paths, - // but project.properties was deleted. Keep the project in the list to force - // a resolve which will display the error. - i++; - continue; - } - - String[] targetPaths = getTargetPaths(target); - - // now get the cached paths - String cache = ProjectHelper.loadStringProperty(iProject, PROPERTY_CONTAINER_CACHE); - if (cache == null) { - // this should not happen. We'll force resolve again anyway. - i++; - continue; - } - - String[] cachedPaths = cache.split(Pattern.quote(PATH_SEPARATOR)); - if (cachedPaths.length < 3 || cachedPaths.length == 4) { - // paths length is wrong. simply resolve the project again - i++; - continue; - } - - // Now we compare the paths. The first 4 can be compared directly. - // because of case sensitiveness we need to use File objects - - if (targetPaths.length != cachedPaths.length) { - // different paths, force resolve again. - i++; - continue; - } - - // compare the main paths (android.jar, main sources, main javadoc) - if (new File(targetPaths[CACHE_INDEX_JAR]).equals( - new File(cachedPaths[CACHE_INDEX_JAR])) == false || - new File(targetPaths[CACHE_INDEX_SRC]).equals( - new File(cachedPaths[CACHE_INDEX_SRC])) == false || - new File(targetPaths[CACHE_INDEX_DOCS_URI]).equals( - new File(cachedPaths[CACHE_INDEX_DOCS_URI])) == false) { - // different paths, force resolve again. - i++; - continue; - } - - if (cachedPaths.length > CACHE_INDEX_OPT_DOCS_URI) { - // compare optional libraries javadoc - if (new File(targetPaths[CACHE_INDEX_OPT_DOCS_URI]).equals( - new File(cachedPaths[CACHE_INDEX_OPT_DOCS_URI])) == false) { - // different paths, force resolve again. - i++; - continue; - } - - // testing the optional jar files is a little bit trickier. - // The order is not guaranteed to be identical. - // From a previous test, we do know however that there is the same number. - // The number of libraries should be low enough that we can simply go through the - // lists manually. - targetLoop: for (int tpi = 4 ; tpi < targetPaths.length; tpi++) { - String targetPath = targetPaths[tpi]; - - // look for a match in the other array - for (int cpi = 4 ; cpi < cachedPaths.length; cpi++) { - if (new File(targetPath).equals(new File(cachedPaths[cpi]))) { - // found a match. Try the next targetPath - continue targetLoop; - } - } - - // if we stop here, we haven't found a match, which means there's a - // discrepancy in the libraries. We force a resolve. - i++; - continue projectLoop; - } - } - - // at the point the check passes, and we can remove the project from the list. - // we do not increment i in this case. - projects.remove(i); - } - } - - /** - * Returns the paths necessary to create the {@link IClasspathEntry} for this targets. - * <p/>The paths are always in the same order. - * <ul> - * <li>Path to android.jar</li> - * <li>Path to the source code for android.jar</li> - * <li>Path to the javadoc for the android platform</li> - * </ul> - * Additionally, if there are optional libraries, the array will contain: - * <ul> - * <li>Path to the libraries javadoc</li> - * <li>Path to the first .jar file</li> - * <li>(more .jar as needed)</li> - * </ul> - */ - private static String[] getTargetPaths(IAndroidTarget target) { - ArrayList<String> paths = new ArrayList<String>(); - - // first, we get the path for android.jar - // The order is: android.jar, source folder, docs folder - paths.add(target.getPath(IAndroidTarget.ANDROID_JAR)); - paths.add(target.getPath(IAndroidTarget.SOURCES)); - paths.add(AdtPlugin.getUrlDoc()); - - // now deal with optional libraries. - IOptionalLibrary[] libraries = target.getOptionalLibraries(); - if (libraries != null) { - // all the optional libraries use the same javadoc, so we start with this - String targetDocPath = target.getPath(IAndroidTarget.DOCS); - if (targetDocPath != null) { - paths.add(ProjectHelper.getJavaDocPath(targetDocPath)); - } else { - // we add an empty string, to always have the same count. - paths.add(""); - } - - // because different libraries could use the same jar file, we make sure we add - // each jar file only once. - HashSet<String> visitedJars = new HashSet<String>(); - for (IOptionalLibrary library : libraries) { - String jarPath = library.getJarPath(); - if (visitedJars.contains(jarPath) == false) { - visitedJars.add(jarPath); - paths.add(jarPath); - } - } - } - - return paths.toArray(new String[paths.size()]); - } - - @Override - public boolean canUpdateClasspathContainer(IPath containerPath, IJavaProject project) { - return true; - } - - @Override - public void requestClasspathContainerUpdate(IPath containerPath, IJavaProject project, - IClasspathContainer containerSuggestion) throws CoreException { - AdtPlugin plugin = AdtPlugin.getDefault(); - - synchronized (Sdk.getLock()) { - boolean sdkIsLoaded = plugin.getSdkLoadStatus() == LoadStatus.LOADED; - - // check if the project has a valid target. - IAndroidTarget target = null; - if (sdkIsLoaded) { - target = Sdk.getCurrent().getTarget(project.getProject()); - } - if (sdkIsLoaded && target != null) { - String[] paths = getTargetPaths(target); - IPath android_lib = new Path(paths[CACHE_INDEX_JAR]); - IClasspathEntry[] entries = containerSuggestion.getClasspathEntries(); - for (int i = 0; i < entries.length; i++) { - IClasspathEntry entry = entries[i]; - if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) { - IPath entryPath = entry.getPath(); - - if (entryPath != null) { - if (entryPath.equals(android_lib)) { - IPath entrySrcPath = entry.getSourceAttachmentPath(); - IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); - if (entrySrcPath != null) { - ProjectHelper.saveStringProperty(root, - getAndroidSourceProperty(target), - entrySrcPath.toString()); - } else { - ProjectHelper.saveStringProperty(root, - getAndroidSourceProperty(target), null); - } - IClasspathAttribute[] extraAttributtes = entry.getExtraAttributes(); - if (extraAttributtes.length == 0) { - ProjectHelper.saveStringProperty(root, PROPERTY_ANDROID_API, - NULL_API_URL); - } - for (int j = 0; j < extraAttributtes.length; j++) { - IClasspathAttribute extraAttribute = extraAttributtes[j]; - String value = extraAttribute.getValue(); - if ((value == null || value.trim().length() == 0) - && IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME - .equals(extraAttribute.getName())) { - value = NULL_API_URL; - } - if (IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME - .equals(extraAttribute.getName())) { - ProjectHelper.saveStringProperty(root, - PROPERTY_ANDROID_API, value); - - } - } - } - } - } - } - rebindClasspathEntries(project.getJavaModel(), containerPath); - } - } - } - - private static void rebindClasspathEntries(IJavaModel model, IPath containerPath) - throws JavaModelException { - ArrayList<IJavaProject> affectedProjects = new ArrayList<IJavaProject>(); - - IJavaProject[] projects = model.getJavaProjects(); - for (int i = 0; i < projects.length; i++) { - IJavaProject project = projects[i]; - IClasspathEntry[] entries = project.getRawClasspath(); - for (int k = 0; k < entries.length; k++) { - IClasspathEntry curr = entries[k]; - if (curr.getEntryKind() == IClasspathEntry.CPE_CONTAINER - && containerPath.equals(curr.getPath())) { - affectedProjects.add(project); - } - } - } - if (!affectedProjects.isEmpty()) { - IJavaProject[] affected = affectedProjects - .toArray(new IJavaProject[affectedProjects.size()]); - updateProjects(affected); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidClasspathContainerPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidClasspathContainerPage.java deleted file mode 100644 index b02765012..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidClasspathContainerPage.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 2010 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.project; - -import com.android.ide.eclipse.adt.AdtConstants; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Path; -import org.eclipse.jdt.core.IClasspathEntry; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.internal.ui.dialogs.StatusInfo; -import org.eclipse.jdt.internal.ui.dialogs.StatusUtil; -import org.eclipse.jdt.ui.wizards.IClasspathContainerPage; -import org.eclipse.jdt.ui.wizards.IClasspathContainerPageExtension; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; - -import java.util.Arrays; - -public class AndroidClasspathContainerPage extends WizardPage implements IClasspathContainerPage, - IClasspathContainerPageExtension { - - private IProject mOwnerProject; - - private String mLibsProjectName; - - private Combo mProjectsCombo; - - private IStatus mCurrStatus; - - private boolean mPageVisible; - - public AndroidClasspathContainerPage() { - super("AndroidClasspathContainerPage"); //$NON-NLS-1$ - mPageVisible = false; - mCurrStatus = new StatusInfo(); - setTitle("Android Libraries"); - setDescription("This container manages classpath entries for Android container"); - } - - @Override - public IClasspathEntry getSelection() { - IPath path = new Path(AdtConstants.CONTAINER_FRAMEWORK); - - final int index = this.mProjectsCombo.getSelectionIndex(); - if (index != -1) { - final String selectedProjectName = this.mProjectsCombo.getItem(index); - - if (this.mOwnerProject == null - || !selectedProjectName.equals(this.mOwnerProject.getName())) { - path = path.append(selectedProjectName); - } - } - - return JavaCore.newContainerEntry(path); - } - - @Override - public void setSelection(final IClasspathEntry cpentry) { - final IPath path = cpentry == null ? null : cpentry.getPath(); - - if (path == null || path.segmentCount() == 1) { - if (this.mOwnerProject != null) { - this.mLibsProjectName = this.mOwnerProject.getName(); - } - } else { - this.mLibsProjectName = path.segment(1); - } - } - - @Override - public void createControl(final Composite parent) { - final Composite composite = new Composite(parent, SWT.NONE); - composite.setLayout(new GridLayout(2, false)); - - final Label label = new Label(composite, SWT.NONE); - label.setText("Project:"); - - final String[] androidProjects = getAndroidProjects(); - - this.mProjectsCombo = new Combo(composite, SWT.READ_ONLY); - this.mProjectsCombo.setItems(androidProjects); - - final int index; - - if (this.mOwnerProject != null) { - index = indexOf(androidProjects, this.mLibsProjectName); - } else { - if (this.mProjectsCombo.getItemCount() > 0) { - index = 0; - } else { - index = -1; - } - } - - if (index != -1) { - this.mProjectsCombo.select(index); - } - - final GridData gd = new GridData(); - gd.grabExcessHorizontalSpace = true; - gd.minimumWidth = 100; - - this.mProjectsCombo.setLayoutData(gd); - - setControl(composite); - } - - @Override - public boolean finish() { - return true; - } - - @Override - public void setVisible(boolean visible) { - super.setVisible(visible); - mPageVisible = visible; - // policy: wizards are not allowed to come up with an error message - if (visible && mCurrStatus.matches(IStatus.ERROR)) { - StatusInfo status = new StatusInfo(); - status.setError(""); //$NON-NLS-1$ - mCurrStatus = status; - } - updateStatus(mCurrStatus); - } - - /** - * Updates the status line and the OK button according to the given status - * - * @param status status to apply - */ - protected void updateStatus(IStatus status) { - mCurrStatus = status; - setPageComplete(!status.matches(IStatus.ERROR)); - if (mPageVisible) { - StatusUtil.applyToStatusLine(this, status); - } - } - - /** - * Updates the status line and the OK button according to the status - * evaluate from an array of status. The most severe error is taken. In case - * that two status with the same severity exists, the status with lower - * index is taken. - * - * @param status the array of status - */ - protected void updateStatus(IStatus[] status) { - updateStatus(StatusUtil.getMostSevere(status)); - } - - @Override - public void initialize(final IJavaProject project, final IClasspathEntry[] currentEntries) { - this.mOwnerProject = (project == null ? null : project.getProject()); - } - - private static String[] getAndroidProjects() { - IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); - final String[] names = new String[projects.length]; - for (int i = 0; i < projects.length; i++) { - names[i] = projects[i].getName(); - } - Arrays.sort(names); - return names; - } - - private static int indexOf(final String[] array, final String str) { - for (int i = 0; i < array.length; i++) { - if (array[i].equals(str)) { - return i; - } - } - return -1; - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidExportNature.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidExportNature.java deleted file mode 100644 index 218cffe5e..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidExportNature.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2010 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.project; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IProjectNature; -import org.eclipse.core.runtime.CoreException; - -/** - * Project nature for the Android Export Projects. - */ -public class AndroidExportNature implements IProjectNature { - - /** the project this nature object is associated with */ - private IProject mProject; - - /** - * Configures this nature for its project. This is called by the workspace - * when natures are added to the project using - * <code>IProject.setDescription</code> and should not be called directly - * by clients. The nature extension id is added to the list of natures - * before this method is called, and need not be added here. - * - * Exceptions thrown by this method will be propagated back to the caller of - * <code>IProject.setDescription</code>, but the nature will remain in - * the project description. - * - * @see org.eclipse.core.resources.IProjectNature#configure() - * @throws CoreException if configuration fails. - */ - @Override - public void configure() throws CoreException { - // nothing to do. - } - - /** - * De-configures this nature for its project. This is called by the - * workspace when natures are removed from the project using - * <code>IProject.setDescription</code> and should not be called directly - * by clients. The nature extension id is removed from the list of natures - * before this method is called, and need not be removed here. - * - * Exceptions thrown by this method will be propagated back to the caller of - * <code>IProject.setDescription</code>, but the nature will still be - * removed from the project description. - * - * The Android nature removes the custom pre builder and APK builder. - * - * @see org.eclipse.core.resources.IProjectNature#deconfigure() - * @throws CoreException if configuration fails. - */ - @Override - public void deconfigure() throws CoreException { - // nothing to do - } - - /** - * Returns the project to which this project nature applies. - * - * @return the project handle - * @see org.eclipse.core.resources.IProjectNature#getProject() - */ - @Override - public IProject getProject() { - return mProject; - } - - /** - * Sets the project to which this nature applies. Used when instantiating - * this project nature runtime. This is called by - * <code>IProject.create()</code> or - * <code>IProject.setDescription()</code> and should not be called - * directly by clients. - * - * @param project the project to which this nature applies - * @see org.eclipse.core.resources.IProjectNature#setProject(org.eclipse.core.resources.IProject) - */ - @Override - public void setProject(IProject project) { - mProject = project; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidManifestHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidManifestHelper.java deleted file mode 100644 index eaa309668..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidManifestHelper.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * 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.project; - -import com.android.ide.common.xml.AndroidManifestParser; -import com.android.ide.common.xml.ManifestData; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.project.XmlErrorHandler.XmlErrorListener; -import com.android.ide.eclipse.adt.io.IFileWrapper; -import com.android.io.FileWrapper; -import com.android.io.IAbstractFile; -import com.android.io.StreamException; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IProject; -import org.eclipse.jdt.core.IJavaProject; -import org.xml.sax.SAXException; - -import java.io.FileNotFoundException; -import java.io.IOException; - -import javax.xml.parsers.ParserConfigurationException; - -public class AndroidManifestHelper { - - /** - * Parses the Android Manifest, and returns an object containing the result of the parsing. - * <p/> - * This method can also gather XML error during the parsing. This is done by using an - * {@link XmlErrorHandler} to mark the files in case of error, as well as a given - * {@link XmlErrorListener}. To use a different error handler, consider using - * {@link AndroidManifestParser#parse(IAbstractFile, boolean, com.android.sdklib.xml.AndroidManifestParser.ManifestErrorHandler)} - * directly. - * - * @param manifestFile the {@link IFile} representing the manifest file. - * @param gatherData indicates whether the parsing will extract data from the manifest. If null, - * the method will always return null. - * @param errorListener an optional error listener. If non null, then the parser will also - * look for XML errors. - * @return an {@link ManifestData} or null if the parsing failed. - * @throws ParserConfigurationException - * @throws StreamException - * @throws IOException - * @throws SAXException - */ - public static ManifestData parseUnchecked( - IAbstractFile manifestFile, - boolean gatherData, - XmlErrorListener errorListener) throws SAXException, IOException, - StreamException, ParserConfigurationException { - if (manifestFile != null) { - IFile eclipseFile = null; - if (manifestFile instanceof IFileWrapper) { - eclipseFile = ((IFileWrapper)manifestFile).getIFile(); - } - XmlErrorHandler errorHandler = null; - if (errorListener != null) { - errorHandler = new XmlErrorHandler(eclipseFile, errorListener); - } - - return AndroidManifestParser.parse(manifestFile, gatherData, errorHandler); - } - - return null; - } - - /** - * Parses the Android Manifest, and returns an object containing the result of the parsing. - * <p/> - * This method can also gather XML error during the parsing. This is done by using an - * {@link XmlErrorHandler} to mark the files in case of error, as well as a given - * {@link XmlErrorListener}. To use a different error handler, consider using - * {@link AndroidManifestParser#parse(IAbstractFile, boolean, com.android.sdklib.xml.AndroidManifestParser.ManifestErrorHandler)} - * directly. - * - * @param manifestFile the {@link IFile} representing the manifest file. - * @param gatherData indicates whether the parsing will extract data from the manifest. If null, - * the method will always return null. - * @param errorListener an optional error listener. If non null, then the parser will also - * look for XML errors. - * @return an {@link ManifestData} or null if the parsing failed. - */ - public static ManifestData parse( - IAbstractFile manifestFile, - boolean gatherData, - XmlErrorListener errorListener) { - try { - return parseUnchecked(manifestFile, gatherData, errorListener); - } catch (ParserConfigurationException e) { - AdtPlugin.logAndPrintError(e, AndroidManifestHelper.class.getCanonicalName(), - "Bad parser configuration for %s: %s", - manifestFile.getOsLocation(), - e.getMessage()); - } catch (SAXException e) { - AdtPlugin.logAndPrintError(e, AndroidManifestHelper.class.getCanonicalName(), - "Parser exception for %s: %s", - manifestFile.getOsLocation(), - e.getMessage()); - } catch (IOException e) { - // Don't log a console error when failing to read a non-existing file - if (!(e instanceof FileNotFoundException)) { - AdtPlugin.logAndPrintError(e, AndroidManifestHelper.class.getCanonicalName(), - "I/O error for %s: %s", - manifestFile.getOsLocation(), - e.getMessage()); - } - } catch (StreamException e) { - AdtPlugin.logAndPrintError(e, AndroidManifestHelper.class.getCanonicalName(), - "Unable to read %s: %s", - manifestFile.getOsLocation(), - e.getMessage()); - } - - return null; - } - - /** - * Parses the Android Manifest for a given project, and returns an object containing - * the result of the parsing. - * <p/> - * This method can also gather XML error during the parsing. This is done by using an - * {@link XmlErrorHandler} to mark the files in case of error, as well as a given - * {@link XmlErrorListener}. To use a different error handler, consider using - * {@link AndroidManifestParser#parse(IAbstractFile, boolean, com.android.sdklib.xml.AndroidManifestParser.ManifestErrorHandler)} - * directly. - * - * @param javaProject the project containing the manifest to parse. - * @param gatherData indicates whether the parsing will extract data from the manifest. If null, - * the method will always return null. - * @param errorListener an optional error listener. If non null, then the parser will also - * look for XML errors. - * @return an {@link ManifestData} or null if the parsing failed. - */ - public static ManifestData parse( - IJavaProject javaProject, - boolean gatherData, - XmlErrorListener errorListener) { - - IFile manifestFile = ProjectHelper.getManifest(javaProject.getProject()); - if (manifestFile != null) { - return parse(new IFileWrapper(manifestFile), gatherData, errorListener); - } - - return null; - } - - /** - * Parses the manifest file only for error check. - * @param manifestFile The manifest file to parse. - * @param errorListener the {@link XmlErrorListener} object being notified of the presence - * of errors. - */ - public static void parseForError(IFile manifestFile, XmlErrorListener errorListener) { - parse(new IFileWrapper(manifestFile), false, errorListener); - } - - /** - * Parses the manifest file, and collects data. - * @param manifestFile The manifest file to parse. - * @return an {@link ManifestData} or null if the parsing failed. - */ - public static ManifestData parseForData(IFile manifestFile) { - return parse(new IFileWrapper(manifestFile), true, null); - } - - /** - * Parses the manifest file, and collects data. - * @param project the project containing the manifest. - * @return an {@link AndroidManifestHelper} or null if the parsing failed. - */ - public static ManifestData parseForData(IProject project) { - IFile manifestFile = ProjectHelper.getManifest(project); - if (manifestFile != null) { - return parse(new IFileWrapper(manifestFile), true, null); - } - - return null; - } - - /** - * Parses the manifest file, and collects data. - * - * @param osManifestFilePath The OS path of the manifest file to parse. - * @return an {@link AndroidManifestHelper} or null if the parsing failed. - */ - public static ManifestData parseForData(String osManifestFilePath) { - return parse(new FileWrapper(osManifestFilePath), true, null); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidNature.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidNature.java deleted file mode 100644 index 3b1c29fe9..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidNature.java +++ /dev/null @@ -1,299 +0,0 @@ -/* - * 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.project; - -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.internal.build.builders.PostCompilerBuilder; -import com.android.ide.eclipse.adt.internal.build.builders.PreCompilerBuilder; -import com.android.ide.eclipse.adt.internal.build.builders.ResourceManagerBuilder; - -import org.eclipse.core.resources.ICommand; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IProjectDescription; -import org.eclipse.core.resources.IProjectNature; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.core.runtime.SubProgressMonitor; -import org.eclipse.jdt.core.JavaCore; - -/** - * Project nature for the Android Projects. - */ -public class AndroidNature implements IProjectNature { - - /** the project this nature object is associated with */ - private IProject mProject; - - /** - * Configures this nature for its project. This is called by the workspace - * when natures are added to the project using - * <code>IProject.setDescription</code> and should not be called directly - * by clients. The nature extension id is added to the list of natures - * before this method is called, and need not be added here. - * - * Exceptions thrown by this method will be propagated back to the caller of - * <code>IProject.setDescription</code>, but the nature will remain in - * the project description. - * - * The Android nature adds the pre-builder and the APK builder if necessary. - * - * @see org.eclipse.core.resources.IProjectNature#configure() - * @throws CoreException if configuration fails. - */ - @Override - public void configure() throws CoreException { - configureResourceManagerBuilder(mProject); - configurePreBuilder(mProject); - configureApkBuilder(mProject); - } - - /** - * De-configures this nature for its project. This is called by the - * workspace when natures are removed from the project using - * <code>IProject.setDescription</code> and should not be called directly - * by clients. The nature extension id is removed from the list of natures - * before this method is called, and need not be removed here. - * - * Exceptions thrown by this method will be propagated back to the caller of - * <code>IProject.setDescription</code>, but the nature will still be - * removed from the project description. - * - * The Android nature removes the custom pre builder and APK builder. - * - * @see org.eclipse.core.resources.IProjectNature#deconfigure() - * @throws CoreException if configuration fails. - */ - @Override - public void deconfigure() throws CoreException { - // remove the android builders - removeBuilder(mProject, ResourceManagerBuilder.ID); - removeBuilder(mProject, PreCompilerBuilder.ID); - removeBuilder(mProject, PostCompilerBuilder.ID); - } - - /** - * Returns the project to which this project nature applies. - * - * @return the project handle - * @see org.eclipse.core.resources.IProjectNature#getProject() - */ - @Override - public IProject getProject() { - return mProject; - } - - /** - * Sets the project to which this nature applies. Used when instantiating - * this project nature runtime. This is called by - * <code>IProject.create()</code> or - * <code>IProject.setDescription()</code> and should not be called - * directly by clients. - * - * @param project the project to which this nature applies - * @see org.eclipse.core.resources.IProjectNature#setProject(org.eclipse.core.resources.IProject) - */ - @Override - public void setProject(IProject project) { - mProject = project; - } - - /** - * Adds the Android Nature and the Java Nature to the project if it doesn't - * already have them. - * - * @param project An existing or new project to update - * @param monitor An optional progress monitor. Can be null. - * @param addAndroidNature true if the Android Nature should be added to the project; false to - * add only the Java nature. - * @throws CoreException if fails to change the nature. - */ - public static synchronized void setupProjectNatures(IProject project, - IProgressMonitor monitor, boolean addAndroidNature) throws CoreException { - if (project == null || !project.isOpen()) return; - if (monitor == null) monitor = new NullProgressMonitor(); - - // Add the natures. We need to add the Java nature first, so it adds its builder to the - // project first. This way, when the android nature is added, we can control where to put - // the android builders in relation to the java builder. - // Adding the java nature after the android one, would place the java builder before the - // android builders. - addNatureToProjectDescription(project, JavaCore.NATURE_ID, monitor); - if (addAndroidNature) { - addNatureToProjectDescription(project, AdtConstants.NATURE_DEFAULT, monitor); - } - } - - /** - * Add the specified nature to the specified project. The nature is only - * added if not already present. - * <p/> - * Android Natures are always inserted at the beginning of the list of natures in order to - * have the jdt views/dialogs display the proper icon. - * - * @param project The project to modify. - * @param natureId The Id of the nature to add. - * @param monitor An existing progress monitor. - * @throws CoreException if fails to change the nature. - */ - private static void addNatureToProjectDescription(IProject project, - String natureId, IProgressMonitor monitor) throws CoreException { - if (!project.hasNature(natureId)) { - - IProjectDescription description = project.getDescription(); - String[] natures = description.getNatureIds(); - String[] newNatures = new String[natures.length + 1]; - - // Android natures always come first. - if (natureId.equals(AdtConstants.NATURE_DEFAULT)) { - System.arraycopy(natures, 0, newNatures, 1, natures.length); - newNatures[0] = natureId; - } else { - System.arraycopy(natures, 0, newNatures, 0, natures.length); - newNatures[natures.length] = natureId; - } - - description.setNatureIds(newNatures); - project.setDescription(description, new SubProgressMonitor(monitor, 10)); - } - } - - /** - * Adds the ResourceManagerBuilder, if its not already there. It'll insert - * itself as the first builder. - * @throws CoreException - * - */ - public static void configureResourceManagerBuilder(IProject project) - throws CoreException { - // get the builder list - IProjectDescription desc = project.getDescription(); - ICommand[] commands = desc.getBuildSpec(); - - // look for the builder in case it's already there. - for (int i = 0; i < commands.length; ++i) { - if (ResourceManagerBuilder.ID.equals(commands[i].getBuilderName())) { - return; - } - } - - // it's not there, lets add it at the beginning of the builders - ICommand[] newCommands = new ICommand[commands.length + 1]; - System.arraycopy(commands, 0, newCommands, 1, commands.length); - ICommand command = desc.newCommand(); - command.setBuilderName(ResourceManagerBuilder.ID); - newCommands[0] = command; - desc.setBuildSpec(newCommands); - project.setDescription(desc, null); - } - - /** - * Adds the PreCompilerBuilder if its not already there. It'll check for - * presence of the ResourceManager and insert itself right after. - * @param project - * @throws CoreException - */ - public static void configurePreBuilder(IProject project) - throws CoreException { - // get the builder list - IProjectDescription desc = project.getDescription(); - ICommand[] commands = desc.getBuildSpec(); - - // look for the builder in case it's already there. - for (int i = 0; i < commands.length; ++i) { - if (PreCompilerBuilder.ID.equals(commands[i].getBuilderName())) { - return; - } - } - - // we need to add it after the resource manager builder. - // Let's look for it - int index = -1; - for (int i = 0; i < commands.length; ++i) { - if (ResourceManagerBuilder.ID.equals(commands[i].getBuilderName())) { - index = i; - break; - } - } - - // we're inserting after - index++; - - // do the insertion - - // copy the builders before. - ICommand[] newCommands = new ICommand[commands.length + 1]; - System.arraycopy(commands, 0, newCommands, 0, index); - - // insert the new builder - ICommand command = desc.newCommand(); - command.setBuilderName(PreCompilerBuilder.ID); - newCommands[index] = command; - - // copy the builder after - System.arraycopy(commands, index, newCommands, index + 1, commands.length-index); - - // set the new builders in the project - desc.setBuildSpec(newCommands); - project.setDescription(desc, null); - } - - public static void configureApkBuilder(IProject project) - throws CoreException { - // Add the .apk builder at the end if it's not already there - IProjectDescription desc = project.getDescription(); - ICommand[] commands = desc.getBuildSpec(); - - for (int i = 0; i < commands.length; ++i) { - if (PostCompilerBuilder.ID.equals(commands[i].getBuilderName())) { - return; - } - } - - ICommand[] newCommands = new ICommand[commands.length + 1]; - System.arraycopy(commands, 0, newCommands, 0, commands.length); - ICommand command = desc.newCommand(); - command.setBuilderName(PostCompilerBuilder.ID); - newCommands[commands.length] = command; - desc.setBuildSpec(newCommands); - project.setDescription(desc, null); - } - - /** - * Removes a builder from the project. - * @param project The project to remove the builder from. - * @param id The String ID of the builder to remove. - * @return true if the builder was found and removed. - * @throws CoreException - */ - public static boolean removeBuilder(IProject project, String id) throws CoreException { - IProjectDescription description = project.getDescription(); - ICommand[] commands = description.getBuildSpec(); - for (int i = 0; i < commands.length; ++i) { - if (id.equals(commands[i].getBuilderName())) { - ICommand[] newCommands = new ICommand[commands.length - 1]; - System.arraycopy(commands, 0, newCommands, 0, i); - System.arraycopy(commands, i + 1, newCommands, i, commands.length - i - 1); - description.setBuildSpec(newCommands); - project.setDescription(description, null); - return true; - } - } - - return false; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ApkInstallManager.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ApkInstallManager.java deleted file mode 100644 index 903914684..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ApkInstallManager.java +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright (C) 2009 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.project; - -import com.android.ddmlib.AndroidDebugBridge; -import com.android.ddmlib.AndroidDebugBridge.IDebugBridgeChangeListener; -import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener; -import com.android.ddmlib.IDevice; -import com.android.ddmlib.MultiLineReceiver; -import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor; -import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor.IProjectListener; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.IPath; - -import java.util.HashSet; -import java.util.Iterator; - -/** - * Registers which apk was installed on which device. - * <p/> - * The goal of this class is to remember the installation of APKs on devices, and provide - * information about whether a new APK should be installed on a device prior to running the - * application from a launch configuration. - * <p/> - * The manager uses {@link IProject} and {@link IDevice} to identify the target device and the - * (project generating the) APK. This ensures that disconnected and reconnected devices will - * always receive new APKs (since the version may not match). - * <p/> - * This is a singleton. To get the instance, use {@link #getInstance()} - */ -public final class ApkInstallManager { - - private final static ApkInstallManager sThis = new ApkInstallManager(); - - /** - * Internal struct to associate a project and a device. - */ - private final static class ApkInstall { - public ApkInstall(IProject project, String packageName, IDevice device) { - this.project = project; - this.packageName = packageName; - this.device = device; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof ApkInstall) { - ApkInstall apkObj = (ApkInstall)obj; - - return (device == apkObj.device && project.equals(apkObj.project) && - packageName.equals(apkObj.packageName)); - } - - return false; - } - - @Override - public int hashCode() { - return (device.getSerialNumber() + project.getName() + packageName).hashCode(); - } - - final IProject project; - final String packageName; - final IDevice device; - } - - /** - * Receiver and parser for the "pm path package" command. - */ - private final static class PmReceiver extends MultiLineReceiver { - boolean foundPackage = false; - @Override - public void processNewLines(String[] lines) { - // if the package if found, then pm will show a line starting with "package:/" - if (foundPackage == false) { // just in case this is called several times for multilines - for (String line : lines) { - if (line.startsWith("package:/")) { - foundPackage = true; - break; - } - } - } - } - - @Override - public boolean isCancelled() { - return false; - } - } - - /** - * Hashset of the list of installed package. Hashset used to ensure we don't re-add new - * objects for the same app. - */ - private final HashSet<ApkInstall> mInstallList = new HashSet<ApkInstall>(); - - public static ApkInstallManager getInstance() { - return sThis; - } - - /** - * Registers an installation of <var>project</var> onto <var>device</var> - * @param project The project that was installed. - * @param packageName the package name of the apk - * @param device The device that received the installation. - */ - public void registerInstallation(IProject project, String packageName, IDevice device) { - synchronized (mInstallList) { - mInstallList.add(new ApkInstall(project, packageName, device)); - } - } - - /** - * Returns whether a <var>project</var> was installed on the <var>device</var>. - * @param project the project that may have been installed. - * @param device the device that may have received the installation. - * @return - */ - public boolean isApplicationInstalled(IProject project, String packageName, IDevice device) { - synchronized (mInstallList) { - ApkInstall found = null; - for (ApkInstall install : mInstallList) { - if (project.equals(install.project) && packageName.equals(install.packageName) && - device == install.device) { - found = install; - break; - } - } - - // check the app is still installed. - if (found != null) { - try { - PmReceiver receiver = new PmReceiver(); - found.device.executeShellCommand("pm path " + packageName, receiver); - if (receiver.foundPackage == false) { - mInstallList.remove(found); - } - - return receiver.foundPackage; - } catch (Exception e) { - // failed to query pm? force reinstall. - return false; - } - } - } - return false; - } - - /** - * Resets registered installations for a specific {@link IProject}. - * <p/>This ensures that {@link #isApplicationInstalled(IProject, IDevice)} will always return - * <code>null</code> for this specified project, for any device. - * @param project the project for which to reset all installations. - */ - public void resetInstallationFor(IProject project) { - synchronized (mInstallList) { - Iterator<ApkInstall> iterator = mInstallList.iterator(); - while (iterator.hasNext()) { - ApkInstall install = iterator.next(); - if (install.project.equals(project)) { - iterator.remove(); - } - } - } - } - - private ApkInstallManager() { - AndroidDebugBridge.addDeviceChangeListener(mDeviceChangeListener); - AndroidDebugBridge.addDebugBridgeChangeListener(mDebugBridgeListener); - GlobalProjectMonitor.getMonitor().addProjectListener(mProjectListener); - } - - private IDebugBridgeChangeListener mDebugBridgeListener = new IDebugBridgeChangeListener() { - /** - * Responds to a bridge change by clearing the full installation list. - * - * @see IDebugBridgeChangeListener#bridgeChanged(AndroidDebugBridge) - */ - @Override - public void bridgeChanged(AndroidDebugBridge bridge) { - // the bridge changed, there is no way to know which IDevice will be which. - // We reset everything - synchronized (mInstallList) { - mInstallList.clear(); - } - } - }; - - private IDeviceChangeListener mDeviceChangeListener = new IDeviceChangeListener() { - /** - * Responds to a device being disconnected by removing all installations related - * to this device. - * - * @see IDeviceChangeListener#deviceDisconnected(IDevice) - */ - @Override - public void deviceDisconnected(IDevice device) { - synchronized (mInstallList) { - Iterator<ApkInstall> iterator = mInstallList.iterator(); - while (iterator.hasNext()) { - ApkInstall install = iterator.next(); - if (install.device == device) { - iterator.remove(); - } - } - } - } - - @Override - public void deviceChanged(IDevice device, int changeMask) { - // nothing to do. - } - - @Override - public void deviceConnected(IDevice device) { - // nothing to do. - } - }; - - private IProjectListener mProjectListener = new IProjectListener() { - /** - * Responds to a closed project by resetting all its installation. - * - * @see IProjectListener#projectClosed(IProject) - */ - @Override - public void projectClosed(IProject project) { - resetInstallationFor(project); - } - - /** - * Responds to a deleted project by resetting all its installation. - * - * @see IProjectListener#projectDeleted(IProject) - */ - @Override - public void projectDeleted(IProject project) { - resetInstallationFor(project); - } - - @Override - public void projectOpened(IProject project) { - // nothing to do. - } - - @Override - public void projectOpenedWithWorkspace(IProject project) { - // nothing to do. - } - - @Override - public void allProjectsOpenedWithWorkspace() { - // nothing to do. - } - - @Override - public void projectRenamed(IProject project, IPath from) { - // project renaming also triggers delete/open events so - // there's nothing to do here (since delete will remove - // whatever's linked to the project from the list). - } - }; -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/BaseClasspathContainerInitializer.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/BaseClasspathContainerInitializer.java deleted file mode 100644 index a58f27d61..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/BaseClasspathContainerInitializer.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2012 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.project; - -import com.android.ide.eclipse.adt.AdtPlugin; - -import org.eclipse.core.resources.IMarker; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.jdt.core.ClasspathContainerInitializer; - -/** - * Base CPC initializer providing support to all our initializer. - * - */ -abstract class BaseClasspathContainerInitializer extends ClasspathContainerInitializer { - - - /** - * Adds an error to a project, or remove all markers if error message is null - * @param project the project to modify - * @param errorMessage the errorMessage or null to remove errors. - * @param markerType the marker type to be used. - * @param outputToConsole whether to output to the console. - */ - protected static void processError(final IProject project, final String errorMessage, - final String markerType, boolean outputToConsole) { - if (errorMessage != null) { - // log the error and put the marker on the project if we can. - if (outputToConsole) { - AdtPlugin.printErrorToConsole(project, errorMessage); - } - - // Use a job to prevent requiring a workspace lock in this thread. - final String fmessage = errorMessage; - Job markerJob = new Job("Android SDK: Resolving error markers") { - @Override - protected IStatus run(IProgressMonitor monitor) { - try { - BaseProjectHelper.markProject(project, - markerType, - fmessage, IMarker.SEVERITY_ERROR, - IMarker.PRIORITY_HIGH); - } catch (CoreException e2) { - AdtPlugin.log(e2, null); - // Don't return e2.getStatus(); the job control will then produce - // a popup with this error, which isn't very interesting for the - // user. - } - - return Status.OK_STATUS; - } - }; - - // build jobs are run after other interactive jobs - markerJob.setPriority(Job.BUILD); - markerJob.setRule(ResourcesPlugin.getWorkspace().getRoot()); - markerJob.schedule(); - } else { - // Use a job to prevent requiring a workspace lock in this thread. - Job markerJob = new Job("Android SDK: Resolving error markers") { - @Override - protected IStatus run(IProgressMonitor monitor) { - try { - if (project.isAccessible()) { - project.deleteMarkers(markerType, true, - IResource.DEPTH_INFINITE); - } - } catch (CoreException e2) { - AdtPlugin.log(e2, null); - } - - return Status.OK_STATUS; - } - }; - - // build jobs are run after other interactive jobs - markerJob.setPriority(Job.BUILD); - markerJob.setRule(ResourcesPlugin.getWorkspace().getRoot()); - markerJob.schedule(); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/BaseProjectHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/BaseProjectHelper.java deleted file mode 100644 index 57632ea87..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/BaseProjectHelper.java +++ /dev/null @@ -1,527 +0,0 @@ -/* - * 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.project; - -import com.android.SdkConstants; -import com.android.annotations.NonNull; -import com.android.annotations.Nullable; -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.google.common.collect.Lists; - -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.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.jdt.core.Flags; -import org.eclipse.jdt.core.IClasspathEntry; -import org.eclipse.jdt.core.IJavaModel; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.IMethod; -import org.eclipse.jdt.core.IType; -import org.eclipse.jdt.core.ITypeHierarchy; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jdt.ui.JavaUI; -import org.eclipse.jdt.ui.actions.OpenJavaPerspectiveAction; -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.IRegion; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.texteditor.IDocumentProvider; -import org.eclipse.ui.texteditor.ITextEditor; - -import java.util.ArrayList; -import java.util.List; - -/** - * Utility methods to manipulate projects. - */ -public final class BaseProjectHelper { - - public static final String TEST_CLASS_OK = null; - - /** - * Project filter to be used with {@link BaseProjectHelper#getAndroidProjects(IProjectFilter)}. - */ - public static interface IProjectFilter { - boolean accept(IProject project); - } - - /** - * returns a list of source classpath for a specified project - * @param javaProject - * @return a list of path relative to the workspace root. - */ - @NonNull - public static List<IPath> getSourceClasspaths(IJavaProject javaProject) { - List<IPath> sourceList = Lists.newArrayList(); - IClasspathEntry[] classpaths = javaProject.readRawClasspath(); - if (classpaths != null) { - for (IClasspathEntry e : classpaths) { - if (e.getEntryKind() == IClasspathEntry.CPE_SOURCE) { - sourceList.add(e.getPath()); - } - } - } - - return sourceList; - } - - /** - * returns a list of source classpath for a specified project - * @param project - * @return a list of path relative to the workspace root. - */ - public static List<IPath> getSourceClasspaths(IProject project) { - IJavaProject javaProject = JavaCore.create(project); - return getSourceClasspaths(javaProject); - } - - /** - * Adds a marker to a file on a specific line. This methods catches thrown - * {@link CoreException}, and returns null instead. - * @param resource the resource to be marked - * @param markerId The id of the marker to add. - * @param message the message associated with the mark - * @param lineNumber the line number where to put the mark. If line is < 1, it puts the marker - * on line 1, - * @param severity the severity of the marker. - * @return the IMarker that was added or null if it failed to add one. - */ - public final static IMarker markResource(IResource resource, String markerId, - String message, int lineNumber, int severity) { - return markResource(resource, markerId, message, lineNumber, -1, -1, severity); - } - - /** - * Adds a marker to a file on a specific line, for a specific range of text. This - * methods catches thrown {@link CoreException}, and returns null instead. - * - * @param resource the resource to be marked - * @param markerId The id of the marker to add. - * @param message the message associated with the mark - * @param lineNumber the line number where to put the mark. If line is < 1, it puts - * the marker on line 1, - * @param startOffset the beginning offset of the marker (relative to the beginning of - * the document, not the line), or -1 for no range - * @param endOffset the ending offset of the marker - * @param severity the severity of the marker. - * @return the IMarker that was added or null if it failed to add one. - */ - @Nullable - public final static IMarker markResource(IResource resource, String markerId, - String message, int lineNumber, int startOffset, int endOffset, int severity) { - if (!resource.isAccessible()) { - return null; - } - - try { - IMarker marker = resource.createMarker(markerId); - marker.setAttribute(IMarker.MESSAGE, message); - marker.setAttribute(IMarker.SEVERITY, severity); - - // if marker is text type, enforce a line number so that it shows in the editor - // somewhere (line 1) - if (lineNumber < 1 && marker.isSubtypeOf(IMarker.TEXT)) { - lineNumber = 1; - } - - if (lineNumber >= 1) { - marker.setAttribute(IMarker.LINE_NUMBER, lineNumber); - } - - if (startOffset != -1) { - marker.setAttribute(IMarker.CHAR_START, startOffset); - marker.setAttribute(IMarker.CHAR_END, endOffset); - } - - // on Windows, when adding a marker to a project, it takes a refresh for the marker - // to show. In order to fix this we're forcing a refresh of elements receiving - // markers (and only the element, not its children), to force the marker display. - resource.refreshLocal(IResource.DEPTH_ZERO, new NullProgressMonitor()); - - return marker; - } catch (CoreException e) { - AdtPlugin.log(e, "Failed to add marker '%1$s' to '%2$s'", //$NON-NLS-1$ - markerId, resource.getFullPath()); - } - - return null; - } - - /** - * Adds a marker to a resource. This methods catches thrown {@link CoreException}, - * and returns null instead. - * @param resource the file to be marked - * @param markerId The id of the marker to add. - * @param message the message associated with the mark - * @param severity the severity of the marker. - * @return the IMarker that was added or null if it failed to add one. - */ - @Nullable - public final static IMarker markResource(IResource resource, String markerId, - String message, int severity) { - return markResource(resource, markerId, message, -1, severity); - } - - /** - * Adds a marker to an {@link IProject}. This method does not catch {@link CoreException}, like - * {@link #markResource(IResource, String, String, int)}. - * - * @param project the project to be marked - * @param markerId The id of the marker to add. - * @param message the message associated with the mark - * @param severity the severity of the marker. - * @param priority the priority of the marker - * @return the IMarker that was added. - * @throws CoreException if the marker cannot be added - */ - @Nullable - public final static IMarker markProject(IProject project, String markerId, - String message, int severity, int priority) throws CoreException { - if (!project.isAccessible()) { - return null; - } - - IMarker marker = project.createMarker(markerId); - marker.setAttribute(IMarker.MESSAGE, message); - marker.setAttribute(IMarker.SEVERITY, severity); - marker.setAttribute(IMarker.PRIORITY, priority); - - // on Windows, when adding a marker to a project, it takes a refresh for the marker - // to show. In order to fix this we're forcing a refresh of elements receiving - // markers (and only the element, not its children), to force the marker display. - project.refreshLocal(IResource.DEPTH_ZERO, new NullProgressMonitor()); - - return marker; - } - - /** - * Tests that a class name is valid for usage in the manifest. - * <p/> - * This tests the class existence, that it can be instantiated (ie it must not be abstract, - * nor non static if enclosed), and that it extends the proper super class (not necessarily - * directly) - * @param javaProject the {@link IJavaProject} containing the class. - * @param className the fully qualified name of the class to test. - * @param superClassName the fully qualified name of the expected super class. - * @param testVisibility if <code>true</code>, the method will check the visibility of the class - * or of its constructors. - * @return {@link #TEST_CLASS_OK} or an error message. - */ - public final static String testClassForManifest(IJavaProject javaProject, String className, - String superClassName, boolean testVisibility) { - try { - // replace $ by . - String javaClassName = className.replaceAll("\\$", "\\."); //$NON-NLS-1$ //$NON-NLS-2$ - - // look for the IType object for this class - IType type = javaProject.findType(javaClassName); - if (type != null && type.exists()) { - // test that the class is not abstract - int flags = type.getFlags(); - if (Flags.isAbstract(flags)) { - return String.format("%1$s is abstract", className); - } - - // test whether the class is public or not. - if (testVisibility && Flags.isPublic(flags) == false) { - // if its not public, it may have a public default constructor, - // which would then be fine. - IMethod basicConstructor = type.getMethod(type.getElementName(), new String[0]); - if (basicConstructor != null && basicConstructor.exists()) { - int constructFlags = basicConstructor.getFlags(); - if (Flags.isPublic(constructFlags) == false) { - return String.format( - "%1$s or its default constructor must be public for the system to be able to instantiate it", - className); - } - } else { - return String.format( - "%1$s must be public, or the system will not be able to instantiate it.", - className); - } - } - - // If it's enclosed, test that it's static. If its declaring class is enclosed - // as well, test that it is also static, and public. - IType declaringType = type; - do { - IType tmpType = declaringType.getDeclaringType(); - if (tmpType != null) { - if (tmpType.exists()) { - flags = declaringType.getFlags(); - if (Flags.isStatic(flags) == false) { - return String.format("%1$s is enclosed, but not static", - declaringType.getFullyQualifiedName()); - } - - flags = tmpType.getFlags(); - if (testVisibility && Flags.isPublic(flags) == false) { - return String.format("%1$s is not public", - tmpType.getFullyQualifiedName()); - } - } else { - // if it doesn't exist, we need to exit so we may as well mark it null. - tmpType = null; - } - } - declaringType = tmpType; - } while (declaringType != null); - - // test the class inherit from the specified super class. - // get the type hierarchy - ITypeHierarchy hierarchy = type.newSupertypeHierarchy(new NullProgressMonitor()); - - // if the super class is not the reference class, it may inherit from - // it so we get its supertype. At some point it will be null and we - // will stop - IType superType = type; - boolean foundProperSuperClass = false; - while ((superType = hierarchy.getSuperclass(superType)) != null && - superType.exists()) { - if (superClassName.equals(superType.getFullyQualifiedName())) { - foundProperSuperClass = true; - } - } - - // didn't find the proper superclass? return false. - if (foundProperSuperClass == false) { - return String.format("%1$s does not extend %2$s", className, superClassName); - } - - return TEST_CLASS_OK; - } else { - return String.format("Class %1$s does not exist", className); - } - } catch (JavaModelException e) { - return String.format("%1$s: %2$s", className, e.getMessage()); - } - } - - /** - * Returns the {@link IJavaProject} for a {@link IProject} object. - * <p/> - * This checks if the project has the Java Nature first. - * @param project - * @return the IJavaProject or null if the project couldn't be created or if the project - * does not have the Java Nature. - * @throws CoreException if this method fails. Reasons include: - * <ul><li>This project does not exist.</li><li>This project is not open.</li></ul> - */ - public static IJavaProject getJavaProject(IProject project) throws CoreException { - if (project != null && project.hasNature(JavaCore.NATURE_ID)) { - return JavaCore.create(project); - } - return null; - } - - /** - * Reveals a specific line in the source file defining a specified class, - * for a specific project. - * @param project - * @param className - * @param line - * @return true if the source was revealed - */ - public static boolean revealSource(IProject project, String className, int line) { - // Inner classes are pointless: All we need is the enclosing type to find the file, and the - // line number. - // Since the anonymous ones will cause IJavaProject#findType to fail, we remove - // all of them. - int pos = className.indexOf('$'); - if (pos != -1) { - className = className.substring(0, pos); - } - - // get the java project - IJavaProject javaProject = JavaCore.create(project); - - try { - // look for the IType matching the class name. - IType result = javaProject.findType(className); - if (result != null && result.exists()) { - // before we show the type in an editor window, we make sure the current - // workbench page has an editor area (typically the ddms perspective doesn't). - IWorkbench workbench = PlatformUI.getWorkbench(); - IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); - IWorkbenchPage page = window.getActivePage(); - if (page.isEditorAreaVisible() == false) { - // no editor area? we open the java perspective. - new OpenJavaPerspectiveAction().run(); - } - - IEditorPart editor = JavaUI.openInEditor(result); - if (editor instanceof ITextEditor) { - // get the text editor that was just opened. - ITextEditor textEditor = (ITextEditor)editor; - - IEditorInput input = textEditor.getEditorInput(); - - // get the location of the line to show. - IDocumentProvider documentProvider = textEditor.getDocumentProvider(); - IDocument document = documentProvider.getDocument(input); - IRegion lineInfo = document.getLineInformation(line - 1); - - // select and reveal the line. - textEditor.selectAndReveal(lineInfo.getOffset(), lineInfo.getLength()); - } - - return true; - } - } catch (JavaModelException e) { - } catch (PartInitException e) { - } catch (BadLocationException e) { - } - - return false; - } - - /** - * Returns the list of android-flagged projects. This list contains projects that are opened - * in the workspace and that are flagged as android project (through the android nature) - * @param filter an optional filter to control which android project are returned. Can be null. - * @return an array of IJavaProject, which can be empty if no projects match. - */ - public static @NonNull IJavaProject[] getAndroidProjects(@Nullable IProjectFilter filter) { - IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); - IJavaModel javaModel = JavaCore.create(workspaceRoot); - - return getAndroidProjects(javaModel, filter); - } - - /** - * Returns the list of android-flagged projects for the specified java Model. - * This list contains projects that are opened in the workspace and that are flagged as android - * project (through the android nature) - * @param javaModel the Java Model object corresponding for the current workspace root. - * @param filter an optional filter to control which android project are returned. Can be null. - * @return an array of IJavaProject, which can be empty if no projects match. - */ - @NonNull - public static IJavaProject[] getAndroidProjects(@NonNull IJavaModel javaModel, - @Nullable IProjectFilter filter) { - // get the java projects - IJavaProject[] javaProjectList = null; - try { - javaProjectList = javaModel.getJavaProjects(); - } - catch (JavaModelException jme) { - return new IJavaProject[0]; - } - - // temp list to build the android project array - ArrayList<IJavaProject> androidProjectList = new ArrayList<IJavaProject>(); - - // loop through the projects and add the android flagged projects to the temp list. - for (IJavaProject javaProject : javaProjectList) { - // get the workspace project object - IProject project = javaProject.getProject(); - - // check if it's an android project based on its nature - if (isAndroidProject(project)) { - if (filter == null || filter.accept(project)) { - androidProjectList.add(javaProject); - } - } - } - - // return the android projects list. - return androidProjectList.toArray(new IJavaProject[androidProjectList.size()]); - } - - /** - * Returns true if the given project is an Android project (e.g. is a Java project - * that also has the Android nature) - * - * @param project the project to test - * @return true if the given project is an Android project - */ - public static boolean isAndroidProject(IProject project) { - // check if it's an android project based on its nature - try { - return project.hasNature(AdtConstants.NATURE_DEFAULT); - } catch (CoreException e) { - // this exception, thrown by IProject.hasNature(), means the project either doesn't - // exist or isn't opened. So, in any case we just skip it (the exception will - // bypass the ArrayList.add() - } - - return false; - } - - /** - * Returns the {@link IFolder} representing the output for the project for Android specific - * files. - * <p> - * The project must be a java project and be opened, or the method will return null. - * @param project the {@link IProject} - * @return an IFolder item or null. - */ - public final static IFolder getJavaOutputFolder(IProject project) { - try { - if (project.isOpen() && project.hasNature(JavaCore.NATURE_ID)) { - // get a java project from the normal project object - IJavaProject javaProject = JavaCore.create(project); - - IPath path = javaProject.getOutputLocation(); - path = path.removeFirstSegments(1); - return project.getFolder(path); - } - } catch (JavaModelException e) { - // Let's do nothing and return null - } catch (CoreException e) { - // Let's do nothing and return null - } - return null; - } - - /** - * Returns the {@link IFolder} representing the output for the project for compiled Java - * files. - * <p> - * The project must be a java project and be opened, or the method will return null. - * @param project the {@link IProject} - * @return an IFolder item or null. - */ - @Nullable - public final static IFolder getAndroidOutputFolder(IProject project) { - try { - if (project.isOpen() && project.hasNature(JavaCore.NATURE_ID)) { - return project.getFolder(SdkConstants.FD_OUTPUT); - } - } catch (JavaModelException e) { - // Let's do nothing and return null - } catch (CoreException e) { - // Let's do nothing and return null - } - return null; - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java deleted file mode 100644 index 56e0c0938..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java +++ /dev/null @@ -1,448 +0,0 @@ -/* - * Copyright (C) 2008 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.project; - -import static com.android.sdklib.internal.project.ProjectProperties.PROPERTY_SDK; - -import com.android.SdkConstants; -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.AndroidPrintStream; -import com.android.ide.eclipse.adt.internal.build.BuildHelper; -import com.android.ide.eclipse.adt.internal.build.DexException; -import com.android.ide.eclipse.adt.internal.build.NativeLibInJarException; -import com.android.ide.eclipse.adt.internal.build.ProguardExecException; -import com.android.ide.eclipse.adt.internal.build.ProguardResultException; -import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; -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.sdklib.BuildToolInfo; -import com.android.sdklib.build.ApkCreationException; -import com.android.sdklib.build.DuplicateFileException; -import com.android.sdklib.internal.project.ProjectProperties; -import com.android.tools.lint.detector.api.LintUtils; -import com.android.xml.AndroidManifest; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IncrementalProjectBuilder; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.swt.SWT; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.FileDialog; -import org.eclipse.swt.widgets.Shell; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.security.PrivateKey; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.jar.JarEntry; -import java.util.jar.JarOutputStream; - -/** - * Export helper to export release version of APKs. - */ -public final class ExportHelper { - private static final String HOME_PROPERTY = "user.home"; //$NON-NLS-1$ - private static final String HOME_PROPERTY_REF = "${" + HOME_PROPERTY + '}'; //$NON-NLS-1$ - private static final String SDK_PROPERTY_REF = "${" + PROPERTY_SDK + '}'; //$NON-NLS-1$ - private final static String TEMP_PREFIX = "android_"; //$NON-NLS-1$ - - /** - * Exports a release version of the application created by the given project. - * @param project the project to export - * @param outputFile the file to write - * @param key the key to used for signing. Can be null. - * @param certificate the certificate used for signing. Can be null. - * @param monitor progress monitor - * @throws CoreException if an error occurs - */ - public static void exportReleaseApk(IProject project, File outputFile, PrivateKey key, - X509Certificate certificate, IProgressMonitor monitor) throws CoreException { - - // the export, takes the output of the precompiler & Java builders so it's - // important to call build in case the auto-build option of the workspace is disabled. - // Also enable dependency building to make sure everything is up to date. - // However do not package the APK since we're going to do it manually here, using a - // different output location. - ProjectHelper.compileInReleaseMode(project, monitor); - - // if either key or certificate is null, ensure the other is null. - if (key == null) { - certificate = null; - } else if (certificate == null) { - key = null; - } - - try { - // check if the manifest declares debuggable as true. While this is a release build, - // debuggable in the manifest will override this and generate a debug build - IResource manifestResource = project.findMember(SdkConstants.FN_ANDROID_MANIFEST_XML); - if (manifestResource.getType() != IResource.FILE) { - throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - String.format("%1$s missing.", SdkConstants.FN_ANDROID_MANIFEST_XML))); - } - - IFileWrapper manifestFile = new IFileWrapper((IFile) manifestResource); - boolean debugMode = AndroidManifest.getDebuggable(manifestFile); - - AndroidPrintStream fakeStream = new AndroidPrintStream(null, null, new OutputStream() { - @Override - public void write(int b) throws IOException { - // do nothing - } - }); - - ProjectState projectState = Sdk.getProjectState(project); - - // get the jumbo mode option - String forceJumboStr = projectState.getProperty(AdtConstants.DEX_OPTIONS_FORCEJUMBO); - Boolean jumbo = Boolean.valueOf(forceJumboStr); - - String dexMergerStr = projectState.getProperty(AdtConstants.DEX_OPTIONS_DISABLE_MERGER); - Boolean dexMerger = Boolean.valueOf(dexMergerStr); - - BuildToolInfo buildToolInfo = getBuildTools(projectState); - - BuildHelper helper = new BuildHelper( - projectState, - buildToolInfo, - fakeStream, fakeStream, - jumbo.booleanValue(), - dexMerger.booleanValue(), - debugMode, false /*verbose*/, - null /*resourceMarker*/); - - // get the list of library projects - List<IProject> libProjects = projectState.getFullLibraryProjects(); - - // Step 1. Package the resources. - - // tmp file for the packaged resource file. To not disturb the incremental builders - // output, all intermediary files are created in tmp files. - File resourceFile = File.createTempFile(TEMP_PREFIX, SdkConstants.DOT_RES); - resourceFile.deleteOnExit(); - - // Make sure the PNG crunch cache is up to date - helper.updateCrunchCache(); - - // get the merged manifest - IFolder androidOutputFolder = BaseProjectHelper.getAndroidOutputFolder(project); - IFile mergedManifestFile = androidOutputFolder.getFile( - SdkConstants.FN_ANDROID_MANIFEST_XML); - - - // package the resources. - helper.packageResources( - mergedManifestFile, - libProjects, - null, // res filter - 0, // versionCode - resourceFile.getParent(), - resourceFile.getName()); - - // Step 2. Convert the byte code to Dalvik bytecode - - // tmp file for the packaged resource file. - File dexFile = File.createTempFile(TEMP_PREFIX, SdkConstants.DOT_DEX); - dexFile.deleteOnExit(); - - ProjectState state = Sdk.getProjectState(project); - String proguardConfig = state.getProperties().getProperty( - ProjectProperties.PROPERTY_PROGUARD_CONFIG); - - boolean runProguard = false; - List<File> proguardConfigFiles = null; - if (proguardConfig != null && proguardConfig.length() > 0) { - // Be tolerant with respect to file and path separators just like - // Ant is. Allow "/" in the property file to mean whatever the file - // separator character is: - if (File.separatorChar != '/' && proguardConfig.indexOf('/') != -1) { - proguardConfig = proguardConfig.replace('/', File.separatorChar); - } - - Iterable<String> paths = LintUtils.splitPath(proguardConfig); - for (String path : paths) { - if (path.startsWith(SDK_PROPERTY_REF)) { - path = AdtPrefs.getPrefs().getOsSdkFolder() + - path.substring(SDK_PROPERTY_REF.length()); - } else if (path.startsWith(HOME_PROPERTY_REF)) { - path = System.getProperty(HOME_PROPERTY) + - path.substring(HOME_PROPERTY_REF.length()); - } - File proguardConfigFile = new File(path); - if (proguardConfigFile.isAbsolute() == false) { - proguardConfigFile = new File(project.getLocation().toFile(), path); - } - if (proguardConfigFile.isFile()) { - if (proguardConfigFiles == null) { - proguardConfigFiles = new ArrayList<File>(); - } - proguardConfigFiles.add(proguardConfigFile); - runProguard = true; - } else { - throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "Invalid proguard configuration file path " + proguardConfigFile - + " does not exist or is not a regular file", null)); - } - } - - // get the proguard file output by aapt - if (proguardConfigFiles != null) { - IFile proguardFile = androidOutputFolder.getFile(AdtConstants.FN_AAPT_PROGUARD); - proguardConfigFiles.add(proguardFile.getLocation().toFile()); - } - } - - Collection<String> dxInput; - - if (runProguard) { - // get all the compiled code paths. This will contain both project output - // folder and jar files. - Collection<String> paths = helper.getCompiledCodePaths(); - - // create a jar file containing all the project output (as proguard cannot - // process folders of .class files). - File inputJar = File.createTempFile(TEMP_PREFIX, SdkConstants.DOT_JAR); - inputJar.deleteOnExit(); - JarOutputStream jos = new JarOutputStream(new FileOutputStream(inputJar)); - - // a list of the other paths (jar files.) - List<String> jars = new ArrayList<String>(); - - for (String path : paths) { - File root = new File(path); - if (root.isDirectory()) { - addFileToJar(jos, root, root); - } else if (root.isFile()) { - jars.add(path); - } - } - jos.close(); - - // destination file for proguard - File obfuscatedJar = File.createTempFile(TEMP_PREFIX, SdkConstants.DOT_JAR); - obfuscatedJar.deleteOnExit(); - - // run proguard - helper.runProguard(proguardConfigFiles, inputJar, jars, obfuscatedJar, - new File(project.getLocation().toFile(), SdkConstants.FD_PROGUARD)); - - helper.setProguardOutput(obfuscatedJar.getAbsolutePath()); - - // dx input is proguard's output - dxInput = Collections.singletonList(obfuscatedJar.getAbsolutePath()); - } else { - // no proguard, simply get all the compiled code path: project output(s) + - // jar file(s) - dxInput = helper.getCompiledCodePaths(); - } - - IJavaProject javaProject = JavaCore.create(project); - - helper.executeDx(javaProject, dxInput, dexFile.getAbsolutePath()); - - // Step 3. Final package - - helper.finalPackage( - resourceFile.getAbsolutePath(), - dexFile.getAbsolutePath(), - outputFile.getAbsolutePath(), - libProjects, - key, - certificate, - null); //resourceMarker - - // success! - } catch (CoreException e) { - throw e; - } catch (ProguardResultException e) { - String msg = String.format("Proguard returned with error code %d. See console", - e.getErrorCode()); - AdtPlugin.printErrorToConsole(project, msg); - AdtPlugin.printErrorToConsole(project, (Object[]) e.getOutput()); - throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - msg, e)); - } catch (ProguardExecException e) { - String msg = String.format("Failed to run proguard: %s", e.getMessage()); - AdtPlugin.printErrorToConsole(project, msg); - throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - msg, e)); - } catch (DuplicateFileException e) { - String msg = String.format( - "Found duplicate file for APK: %1$s\nOrigin 1: %2$s\nOrigin 2: %3$s", - e.getArchivePath(), e.getFile1(), e.getFile2()); - AdtPlugin.printErrorToConsole(project, msg); - throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - e.getMessage(), e)); - } catch (NativeLibInJarException e) { - String msg = e.getMessage(); - - AdtPlugin.printErrorToConsole(project, msg); - AdtPlugin.printErrorToConsole(project, (Object[]) e.getAdditionalInfo()); - throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - e.getMessage(), e)); - } catch (DexException e) { - throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - e.getMessage(), e)); - } catch (ApkCreationException e) { - throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - e.getMessage(), e)); - } catch (Exception e) { - throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "Failed to export application", e)); - } finally { - // move back to a debug build. - // By using a normal build, we'll simply rebuild the debug version, and let the - // builder decide whether to build the full package or not. - ProjectHelper.buildWithDeps(project, IncrementalProjectBuilder.FULL_BUILD, monitor); - project.refreshLocal(IResource.DEPTH_INFINITE, monitor); - } - } - - public static BuildToolInfo getBuildTools(ProjectState projectState) - throws CoreException { - BuildToolInfo buildToolInfo = projectState.getBuildToolInfo(); - if (buildToolInfo == null) { - buildToolInfo = Sdk.getCurrent().getLatestBuildTool(); - } - - if (buildToolInfo == null) { - throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "No Build Tools installed in the SDK.")); - } - return buildToolInfo; - } - - /** - * Exports an unsigned release APK after prompting the user for a location. - * - * <strong>Must be called from the UI thread.</strong> - * - * @param project the project to export - */ - public static void exportUnsignedReleaseApk(final IProject project) { - Shell shell = Display.getCurrent().getActiveShell(); - - // create a default file name for the apk. - String fileName = project.getName() + SdkConstants.DOT_ANDROID_PACKAGE; - - // Pop up the file save window to get the file location - FileDialog fileDialog = new FileDialog(shell, SWT.SAVE); - - fileDialog.setText("Export Project"); - fileDialog.setFileName(fileName); - - final String saveLocation = fileDialog.open(); - if (saveLocation != null) { - new Job("Android Release Export") { - @Override - protected IStatus run(IProgressMonitor monitor) { - try { - exportReleaseApk(project, - new File(saveLocation), - null, //key - null, //certificate - monitor); - - // this is unsigned export. Let's tell the developers to run zip align - AdtPlugin.displayWarning("Android IDE Plug-in", String.format( - "An unsigned package of the application was saved at\n%1$s\n\n" + - "Before publishing the application you will need to:\n" + - "- Sign the application with your release key,\n" + - "- run zipalign on the signed package. ZipAlign is located in <SDK>/tools/\n\n" + - "Aligning applications allows Android to use application resources\n" + - "more efficiently.", saveLocation)); - - return Status.OK_STATUS; - } catch (CoreException e) { - AdtPlugin.displayError("Android IDE Plug-in", String.format( - "Error exporting application:\n\n%1$s", e.getMessage())); - return e.getStatus(); - } - } - }.schedule(); - } - } - - /** - * Adds a file to a jar file. - * The <var>rootDirectory</var> dictates the path of the file inside the jar file. It must be - * a parent of <var>file</var>. - * @param jar the jar to add the file to - * @param file the file to add - * @param rootDirectory the rootDirectory. - * @throws IOException - */ - private static void addFileToJar(JarOutputStream jar, File file, File rootDirectory) - throws IOException { - if (file.isDirectory()) { - if (file.getName().equals("META-INF") == false) { - for (File child: file.listFiles()) { - addFileToJar(jar, child, rootDirectory); - } - } - } else if (file.isFile()) { - String rootPath = rootDirectory.getAbsolutePath(); - String path = file.getAbsolutePath(); - path = path.substring(rootPath.length()).replace("\\", "/"); //$NON-NLS-1$ //$NON-NLS-2$ - if (path.charAt(0) == '/') { - path = path.substring(1); - } - - JarEntry entry = new JarEntry(path); - entry.setTime(file.lastModified()); - jar.putNextEntry(entry); - - // put the content of the file. - byte[] buffer = new byte[1024]; - int count; - BufferedInputStream bis = null; - try { - bis = new BufferedInputStream(new FileInputStream(file)); - while ((count = bis.read(buffer)) != -1) { - jar.write(buffer, 0, count); - } - } finally { - if (bis != null) { - try { - bis.close(); - } catch (IOException ignore) { - } - } - } - jar.closeEntry(); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/FixLaunchConfig.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/FixLaunchConfig.java deleted file mode 100644 index e311bfb0b..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/FixLaunchConfig.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * 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.project; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.launch.LaunchConfigDelegate; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.debug.core.DebugPlugin; -import org.eclipse.debug.core.ILaunchConfiguration; -import org.eclipse.debug.core.ILaunchConfigurationType; -import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; -import org.eclipse.debug.core.ILaunchManager; -import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; - -import java.util.ArrayList; - -/** - * Class to fix the launch configuration of a project if the java package - * defined in the manifest has been changed.<br> - * This fix can be done synchronously, or asynchronously.<br> - * <code>start()</code> will start a thread that will do the fix.<br> - * <code>run()</code> will do the fix in the current thread.<br><br> - * By default, the fix first display a dialog to the user asking if he/she wants to - * do the fix. This can be overriden by calling <code>setDisplayPrompt(false)</code>. - * - */ -public class FixLaunchConfig extends Thread { - - private IProject mProject; - private String mOldPackage; - private String mNewPackage; - - private boolean mDisplayPrompt = true; - - public FixLaunchConfig(IProject project, String oldPackage, String newPackage) { - super(); - - mProject = project; - mOldPackage = oldPackage; - mNewPackage = newPackage; - } - - /** - * Set the display prompt. If true run()/start() first ask the user if he/she wants - * to fix the Launch Config - * @param displayPrompt - */ - public void setDisplayPrompt(boolean displayPrompt) { - mDisplayPrompt = displayPrompt; - } - - /** - * Fix the Launch configurations. - */ - @Override - public void run() { - - if (mDisplayPrompt) { - // ask the user if he really wants to fix the launch config - boolean res = AdtPlugin.displayPrompt( - "Launch Configuration Update", - "The package definition in the manifest changed.\nDo you want to update your Launch Configuration(s)?"); - - if (res == false) { - return; - } - } - - // get the list of config for the project - String projectName = mProject.getName(); - ILaunchConfiguration[] configs = findConfigs(mProject.getName()); - - // loop through all the config and update the package - for (ILaunchConfiguration config : configs) { - try { - // get the working copy so that we can make changes. - ILaunchConfigurationWorkingCopy copy = config.getWorkingCopy(); - - // get the attributes for the activity - String activity = config.getAttribute(LaunchConfigDelegate.ATTR_ACTIVITY, - ""); //$NON-NLS-1$ - - // manifests can define activities that are not in the defined package, - // so we need to make sure the activity is inside the old package. - if (activity.startsWith(mOldPackage)) { - // create the new activity - activity = mNewPackage + activity.substring(mOldPackage.length()); - - // put it in the copy - copy.setAttribute(LaunchConfigDelegate.ATTR_ACTIVITY, activity); - - // save the config - copy.doSave(); - } - } catch (CoreException e) { - // couldn't get the working copy. we output the error in the console - String msg = String.format("Failed to modify %1$s: %2$s", projectName, - e.getMessage()); - AdtPlugin.printErrorToConsole(mProject, msg); - } - } - - } - - /** - * Looks for and returns all existing Launch Configuration object for a - * specified project. - * @param projectName The name of the project - * @return all the ILaunchConfiguration object. If none are present, an empty array is - * returned. - */ - private static ILaunchConfiguration[] findConfigs(String projectName) { - // get the launch manager - ILaunchManager manager = DebugPlugin.getDefault().getLaunchManager(); - - // now get the config type for our particular android type. - ILaunchConfigurationType configType = manager. - getLaunchConfigurationType(LaunchConfigDelegate.ANDROID_LAUNCH_TYPE_ID); - - // create a temp list to hold all the valid configs - ArrayList<ILaunchConfiguration> list = new ArrayList<ILaunchConfiguration>(); - - try { - ILaunchConfiguration[] configs = manager.getLaunchConfigurations(configType); - - for (ILaunchConfiguration config : configs) { - if (config.getAttribute( - IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, - "").equals(projectName)) { //$NON-NLS-1$ - list.add(config); - } - } - } catch (CoreException e) { - } - - return list.toArray(new ILaunchConfiguration[list.size()]); - - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/FolderDecorator.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/FolderDecorator.java deleted file mode 100644 index 054890f86..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/FolderDecorator.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2008 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.project; - -import com.android.SdkConstants; -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.AdtPlugin; - -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.jface.viewers.IDecoration; -import org.eclipse.jface.viewers.ILabelDecorator; -import org.eclipse.jface.viewers.ILabelProviderListener; -import org.eclipse.jface.viewers.ILightweightLabelDecorator; - -/** - * A {@link ILabelDecorator} associated with an org.eclipse.ui.decorators extension. - * This is used to add android icons in some special folders in the package explorer. - */ -public class FolderDecorator implements ILightweightLabelDecorator { - - private ImageDescriptor mDescriptor; - - public FolderDecorator() { - mDescriptor = AdtPlugin.getImageDescriptor("/icons/android_project.png"); //$NON-NLS-1$ - } - - @Override - public void decorate(Object element, IDecoration decoration) { - if (element instanceof IFolder) { - IFolder folder = (IFolder)element; - - // get the project and make sure this is an android project - IProject project = folder.getProject(); - if (project == null || !project.exists() || !folder.exists()) { - return; - } - - try { - if (project.hasNature(AdtConstants.NATURE_DEFAULT)) { - // check the folder is directly under the project. - if (folder.getParent().getType() == IResource.PROJECT) { - String name = folder.getName(); - if (name.equals(SdkConstants.FD_ASSETS)) { - doDecoration(decoration, null); - } else if (name.equals(SdkConstants.FD_RESOURCES)) { - doDecoration(decoration, null); - } else if (name.equals(SdkConstants.FD_GEN_SOURCES)) { - doDecoration(decoration, " [Generated Java Files]"); - } else if (name.equals(SdkConstants.FD_NATIVE_LIBS)) { - doDecoration(decoration, null); - } else if (name.equals(SdkConstants.FD_OUTPUT)) { - doDecoration(decoration, null); - } - } - } - } catch (CoreException e) { - // log the error - AdtPlugin.log(e, "Unable to get nature of project '%s'.", project.getName()); - } - } - } - - public void doDecoration(IDecoration decoration, String suffix) { - decoration.addOverlay(mDescriptor, IDecoration.TOP_LEFT); - - if (suffix != null) { - decoration.addSuffix(suffix); - } - } - - @Override - public boolean isLabelProperty(Object element, String property) { - // Property change do not affect the label - return false; - } - - @Override - public void addListener(ILabelProviderListener listener) { - // No state change will affect the rendering. - } - - @Override - public void removeListener(ILabelProviderListener listener) { - // No state change will affect the rendering. - } - - @Override - public void dispose() { - // nothing to dispose - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/LibraryClasspathContainerInitializer.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/LibraryClasspathContainerInitializer.java deleted file mode 100644 index 8fbee4089..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/LibraryClasspathContainerInitializer.java +++ /dev/null @@ -1,641 +0,0 @@ -/* - * Copyright (C) 2011 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.project; - -import static com.android.ide.eclipse.adt.AdtConstants.CONTAINER_DEPENDENCIES; - -import com.android.SdkConstants; -import com.android.ide.common.sdk.LoadStatus; -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.AndroidPrintStream; -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.build.JarListSanitizer; -import com.android.sdklib.build.JarListSanitizer.DifferentLibException; -import com.android.sdklib.build.JarListSanitizer.Sha1Exception; -import com.android.sdklib.build.RenderScriptProcessor; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.core.runtime.Path; -import org.eclipse.jdt.core.IAccessRule; -import org.eclipse.jdt.core.IClasspathAttribute; -import org.eclipse.jdt.core.IClasspathContainer; -import org.eclipse.jdt.core.IClasspathEntry; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.JavaModelException; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Properties; -import java.util.Set; - -public class LibraryClasspathContainerInitializer extends BaseClasspathContainerInitializer { - - private final static String ATTR_SRC = "src"; //$NON-NLS-1$ - private final static String ATTR_DOC = "doc"; //$NON-NLS-1$ - private final static String DOT_PROPERTIES = ".properties"; //$NON-NLS-1$ - - public LibraryClasspathContainerInitializer() { - } - - /** - * Updates the {@link IJavaProject} objects with new library. - * @param androidProjects the projects to update. - * @return <code>true</code> if success, <code>false</code> otherwise. - */ - public static boolean updateProjects(IJavaProject[] androidProjects) { - try { - // Allocate a new AndroidClasspathContainer, and associate it to the library - // container id for each projects. - int projectCount = androidProjects.length; - - IClasspathContainer[] libraryContainers = new IClasspathContainer[projectCount]; - IClasspathContainer[] dependencyContainers = new IClasspathContainer[projectCount]; - for (int i = 0 ; i < projectCount; i++) { - libraryContainers[i] = allocateLibraryContainer(androidProjects[i]); - dependencyContainers[i] = allocateDependencyContainer(androidProjects[i]); - } - - // give each project their new container in one call. - JavaCore.setClasspathContainer( - new Path(AdtConstants.CONTAINER_PRIVATE_LIBRARIES), - androidProjects, libraryContainers, new NullProgressMonitor()); - - JavaCore.setClasspathContainer( - new Path(AdtConstants.CONTAINER_DEPENDENCIES), - androidProjects, dependencyContainers, new NullProgressMonitor()); - return true; - } catch (JavaModelException e) { - return false; - } - } - - /** - * Updates the {@link IJavaProject} objects with new library. - * @param androidProjects the projects to update. - * @return <code>true</code> if success, <code>false</code> otherwise. - */ - public static boolean updateProject(List<ProjectState> projects) { - List<IJavaProject> javaProjectList = new ArrayList<IJavaProject>(projects.size()); - for (ProjectState p : projects) { - IJavaProject javaProject = JavaCore.create(p.getProject()); - if (javaProject != null) { - javaProjectList.add(javaProject); - } - } - - IJavaProject[] javaProjects = javaProjectList.toArray( - new IJavaProject[javaProjectList.size()]); - - return updateProjects(javaProjects); - } - - @Override - public void initialize(IPath containerPath, IJavaProject project) throws CoreException { - if (AdtConstants.CONTAINER_PRIVATE_LIBRARIES.equals(containerPath.toString())) { - IClasspathContainer libraries = allocateLibraryContainer(project); - if (libraries != null) { - JavaCore.setClasspathContainer(new Path(AdtConstants.CONTAINER_PRIVATE_LIBRARIES), - new IJavaProject[] { project }, - new IClasspathContainer[] { libraries }, - new NullProgressMonitor()); - } - - } else if(AdtConstants.CONTAINER_DEPENDENCIES.equals(containerPath.toString())) { - IClasspathContainer dependencies = allocateDependencyContainer(project); - if (dependencies != null) { - JavaCore.setClasspathContainer(new Path(AdtConstants.CONTAINER_DEPENDENCIES), - new IJavaProject[] { project }, - new IClasspathContainer[] { dependencies }, - new NullProgressMonitor()); - } - } - } - - private static IClasspathContainer allocateLibraryContainer(IJavaProject javaProject) { - final IProject iProject = javaProject.getProject(); - - // check if the project has a valid target. - ProjectState state = Sdk.getProjectState(iProject); - if (state == null) { - // getProjectState should already have logged an error. Just bail out. - return null; - } - - /* - * At this point we're going to gather a list of all that need to go in the - * dependency container. - * - Library project outputs (direct and indirect) - * - Java project output (those can be indirectly referenced through library projects - * or other other Java projects) - * - Jar files: - * + inside this project's libs/ - * + inside the library projects' libs/ - * + inside the referenced Java projects' classpath - */ - List<IClasspathEntry> entries = new ArrayList<IClasspathEntry>(); - - // list of java project dependencies and jar files that will be built while - // going through the library projects. - Set<File> jarFiles = new HashSet<File>(); - Set<IProject> refProjects = new HashSet<IProject>(); - - // process all the libraries - - List<IProject> libProjects = state.getFullLibraryProjects(); - for (IProject libProject : libProjects) { - // process all of the library project's dependencies - getDependencyListFromClasspath(libProject, refProjects, jarFiles, true); - } - - // now process this projects' referenced projects only. - processReferencedProjects(iProject, refProjects, jarFiles); - - // and the content of its libs folder - getJarListFromLibsFolder(iProject, jarFiles); - - // now add a classpath entry for each Java project (this is a set so dups are already - // removed) - for (IProject p : refProjects) { - entries.add(JavaCore.newProjectEntry(p.getFullPath(), true /*isExported*/)); - } - - entries.addAll(convertJarsToClasspathEntries(iProject, jarFiles)); - - return allocateContainer(javaProject, entries, new Path(AdtConstants.CONTAINER_PRIVATE_LIBRARIES), - "Android Private Libraries"); - } - - private static List<IClasspathEntry> convertJarsToClasspathEntries(final IProject iProject, - Set<File> jarFiles) { - List<IClasspathEntry> entries = new ArrayList<IClasspathEntry>(jarFiles.size()); - - // and process the jar files list, but first sanitize it to remove dups. - JarListSanitizer sanitizer = new JarListSanitizer( - iProject.getFolder(SdkConstants.FD_OUTPUT).getLocation().toFile(), - new AndroidPrintStream(iProject, null /*prefix*/, - AdtPlugin.getOutStream())); - - String errorMessage = null; - - try { - List<File> sanitizedList = sanitizer.sanitize(jarFiles); - - for (File jarFile : sanitizedList) { - if (jarFile instanceof CPEFile) { - CPEFile cpeFile = (CPEFile) jarFile; - IClasspathEntry e = cpeFile.getClasspathEntry(); - - entries.add(JavaCore.newLibraryEntry( - e.getPath(), - e.getSourceAttachmentPath(), - e.getSourceAttachmentRootPath(), - e.getAccessRules(), - e.getExtraAttributes(), - true /*isExported*/)); - } else { - String jarPath = jarFile.getAbsolutePath(); - - IPath sourceAttachmentPath = null; - IClasspathAttribute javaDocAttribute = null; - - File jarProperties = new File(jarPath + DOT_PROPERTIES); - if (jarProperties.isFile()) { - Properties p = new Properties(); - InputStream is = null; - try { - p.load(is = new FileInputStream(jarProperties)); - - String value = p.getProperty(ATTR_SRC); - if (value != null) { - File srcPath = getFile(jarFile, value); - - if (srcPath.exists()) { - sourceAttachmentPath = new Path(srcPath.getAbsolutePath()); - } - } - - value = p.getProperty(ATTR_DOC); - if (value != null) { - File docPath = getFile(jarFile, value); - if (docPath.exists()) { - try { - javaDocAttribute = JavaCore.newClasspathAttribute( - IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME, - docPath.toURI().toURL().toString()); - } catch (MalformedURLException e) { - AdtPlugin.log(e, "Failed to process 'doc' attribute for %s", - jarProperties.getAbsolutePath()); - } - } - } - - } catch (FileNotFoundException e) { - // shouldn't happen since we check upfront - } catch (IOException e) { - AdtPlugin.log(e, "Failed to read %s", jarProperties.getAbsolutePath()); - } finally { - if (is != null) { - try { - is.close(); - } catch (IOException e) { - // ignore - } - } - } - } - - if (javaDocAttribute != null) { - entries.add(JavaCore.newLibraryEntry(new Path(jarPath), - sourceAttachmentPath, null /*sourceAttachmentRootPath*/, - new IAccessRule[0], - new IClasspathAttribute[] { javaDocAttribute }, - true /*isExported*/)); - } else { - entries.add(JavaCore.newLibraryEntry(new Path(jarPath), - sourceAttachmentPath, null /*sourceAttachmentRootPath*/, - true /*isExported*/)); - } - } - } - } catch (DifferentLibException e) { - errorMessage = e.getMessage(); - AdtPlugin.printErrorToConsole(iProject, (Object[]) e.getDetails()); - } catch (Sha1Exception e) { - errorMessage = e.getMessage(); - } - - processError(iProject, errorMessage, AdtConstants.MARKER_DEPENDENCY, - true /*outputToConsole*/); - - return entries; - } - - private static IClasspathContainer allocateDependencyContainer(IJavaProject javaProject) { - final IProject iProject = javaProject.getProject(); - final List<IClasspathEntry> entries = new ArrayList<IClasspathEntry>(); - final Set<File> jarFiles = new HashSet<File>(); - final IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); - - AdtPlugin plugin = AdtPlugin.getDefault(); - if (plugin == null) { // This is totally weird, but I've seen it happen! - return null; - } - - synchronized (Sdk.getLock()) { - boolean sdkIsLoaded = plugin.getSdkLoadStatus() == LoadStatus.LOADED; - - // check if the project has a valid target. - final ProjectState state = Sdk.getProjectState(iProject); - if (state == null) { - // getProjectState should already have logged an error. Just bail out. - return null; - } - - // annotations support for older version of android - if (state.getTarget() != null && state.getTarget().getVersion().getApiLevel() <= 15) { - File annotationsJar = new File(Sdk.getCurrent().getSdkOsLocation(), - SdkConstants.FD_TOOLS + File.separator + SdkConstants.FD_SUPPORT + - File.separator + SdkConstants.FN_ANNOTATIONS_JAR); - - jarFiles.add(annotationsJar); - } - - if (state.getRenderScriptSupportMode()) { - if (!sdkIsLoaded) { - return null; - } - BuildToolInfo buildToolInfo = state.getBuildToolInfo(); - if (buildToolInfo == null) { - buildToolInfo = Sdk.getCurrent().getLatestBuildTool(); - - if (buildToolInfo == null) { - return null; - } - } - - File renderScriptSupportJar = RenderScriptProcessor.getSupportJar( - buildToolInfo.getLocation().getAbsolutePath()); - - jarFiles.add(renderScriptSupportJar); - } - - // process all the libraries - - List<IProject> libProjects = state.getFullLibraryProjects(); - for (IProject libProject : libProjects) { - // get the project output - IFolder outputFolder = BaseProjectHelper.getAndroidOutputFolder(libProject); - - if (outputFolder != null) { // can happen when closing/deleting a library) - IFile jarIFile = outputFolder.getFile(libProject.getName().toLowerCase() + - SdkConstants.DOT_JAR); - - // get the source folder for the library project - List<IPath> srcs = BaseProjectHelper.getSourceClasspaths(libProject); - // find the first non-derived source folder. - IPath sourceFolder = null; - for (IPath src : srcs) { - IFolder srcFolder = workspaceRoot.getFolder(src); - if (srcFolder.isDerived() == false) { - sourceFolder = src; - break; - } - } - - // we can directly add a CPE for this jar as there's no risk of a duplicate. - IClasspathEntry entry = JavaCore.newLibraryEntry( - jarIFile.getLocation(), - sourceFolder, // source attachment path - null, // default source attachment root path. - true /*isExported*/); - - entries.add(entry); - } - } - - entries.addAll(convertJarsToClasspathEntries(iProject, jarFiles)); - - return allocateContainer(javaProject, entries, new Path(CONTAINER_DEPENDENCIES), - "Android Dependencies"); - } - } - - private static IClasspathContainer allocateContainer(IJavaProject javaProject, - List<IClasspathEntry> entries, IPath id, String description) { - - if (AdtPlugin.getDefault() == null) { // This is totally weird, but I've seen it happen! - return null; - } - - // First check that the project has a library-type container. - try { - IClasspathEntry[] rawClasspath = javaProject.getRawClasspath(); - final IClasspathEntry[] oldRawClasspath = rawClasspath; - - boolean foundContainer = false; - for (IClasspathEntry entry : rawClasspath) { - // get the entry and kind - final int kind = entry.getEntryKind(); - - if (kind == IClasspathEntry.CPE_CONTAINER) { - String path = entry.getPath().toString(); - String idString = id.toString(); - if (idString.equals(path)) { - foundContainer = true; - break; - } - } - } - - // if there isn't any, add it. - if (foundContainer == false) { - // add the android container to the array - rawClasspath = ProjectHelper.addEntryToClasspath(rawClasspath, - JavaCore.newContainerEntry(id, true /*isExported*/)); - } - - // set the new list of entries to the project - if (rawClasspath != oldRawClasspath) { - javaProject.setRawClasspath(rawClasspath, new NullProgressMonitor()); - } - } catch (JavaModelException e) { - // This really shouldn't happen, but if it does, simply return null (the calling - // method will fails as well) - return null; - } - - return new AndroidClasspathContainer( - entries.toArray(new IClasspathEntry[entries.size()]), - id, - description, - IClasspathContainer.K_APPLICATION); - } - - private static File getFile(File root, String value) { - File file = new File(value); - if (file.isAbsolute() == false) { - file = new File(root.getParentFile(), value); - } - - return file; - } - - /** - * Finds all the jar files inside a project's libs folder. - * @param project - * @param jarFiles - */ - private static void getJarListFromLibsFolder(IProject project, Set<File> jarFiles) { - IFolder libsFolder = project.getFolder(SdkConstants.FD_NATIVE_LIBS); - if (libsFolder.exists()) { - try { - IResource[] members = libsFolder.members(); - for (IResource member : members) { - if (member.getType() == IResource.FILE && - SdkConstants.EXT_JAR.equalsIgnoreCase(member.getFileExtension())) { - IPath location = member.getLocation(); - if (location != null) { - jarFiles.add(location.toFile()); - } - } - } - } catch (CoreException e) { - // can't get the list? ignore this folder. - } - } - } - - /** - * Process reference projects from the main projects to add indirect dependencies coming - * from Java project. - * @param project the main project - * @param projects the project list to add to - * @param jarFiles the jar list to add to. - */ - private static void processReferencedProjects(IProject project, - Set<IProject> projects, Set<File> jarFiles) { - try { - IProject[] refs = project.getReferencedProjects(); - for (IProject p : refs) { - // ignore if it's an Android project, or if it's not a Java - // Project - if (p.hasNature(JavaCore.NATURE_ID) - && p.hasNature(AdtConstants.NATURE_DEFAULT) == false) { - - // process this project's dependencies - getDependencyListFromClasspath(p, projects, jarFiles, true /*includeJarFiles*/); - } - } - } catch (CoreException e) { - // can't get the referenced projects? ignore - } - } - - /** - * Finds all the dependencies of a given project and add them to a project list and - * a jar list. - * Only classpath entries that are exported are added, and only Java project (not Android - * project) are added. - * - * @param project the project to query - * @param projects the referenced project list to add to - * @param jarFiles the jar list to add to - * @param includeJarFiles whether to include jar files or just projects. This is useful when - * calling on an Android project (value should be <code>false</code>) - */ - private static void getDependencyListFromClasspath(IProject project, Set<IProject> projects, - Set<File> jarFiles, boolean includeJarFiles) { - IJavaProject javaProject = JavaCore.create(project); - IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot(); - - // we could use IJavaProject.getResolvedClasspath directly, but we actually - // want to see the containers themselves. - IClasspathEntry[] classpaths = javaProject.readRawClasspath(); - if (classpaths != null) { - for (IClasspathEntry e : classpaths) { - // ignore entries that are not exported - if (!e.getPath().toString().equals(CONTAINER_DEPENDENCIES) && e.isExported()) { - processCPE(e, javaProject, wsRoot, projects, jarFiles, includeJarFiles); - } - } - } - } - - /** - * Processes a {@link IClasspathEntry} and add it to one of the list if applicable. - * @param entry the entry to process - * @param javaProject the {@link IJavaProject} from which this entry came. - * @param wsRoot the {@link IWorkspaceRoot} - * @param projects the project list to add to - * @param jarFiles the jar list to add to - * @param includeJarFiles whether to include jar files or just projects. This is useful when - * calling on an Android project (value should be <code>false</code>) - */ - private static void processCPE(IClasspathEntry entry, IJavaProject javaProject, - IWorkspaceRoot wsRoot, - Set<IProject> projects, Set<File> jarFiles, boolean includeJarFiles) { - - // if this is a classpath variable reference, we resolve it. - if (entry.getEntryKind() == IClasspathEntry.CPE_VARIABLE) { - entry = JavaCore.getResolvedClasspathEntry(entry); - } - - if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) { - IProject refProject = wsRoot.getProject(entry.getPath().lastSegment()); - try { - // ignore if it's an Android project, or if it's not a Java Project - if (refProject.hasNature(JavaCore.NATURE_ID) && - refProject.hasNature(AdtConstants.NATURE_DEFAULT) == false) { - // add this project to the list - projects.add(refProject); - - // also get the dependency from this project. - getDependencyListFromClasspath(refProject, projects, jarFiles, - true /*includeJarFiles*/); - } - } catch (CoreException exception) { - // can't query the project nature? ignore - } - } else if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) { - if (includeJarFiles) { - handleClasspathLibrary(entry, wsRoot, jarFiles); - } - } else if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) { - // get the container and its content - try { - IClasspathContainer container = JavaCore.getClasspathContainer( - entry.getPath(), javaProject); - // ignore the system and default_system types as they represent - // libraries that are part of the runtime. - if (container != null && - container.getKind() == IClasspathContainer.K_APPLICATION) { - IClasspathEntry[] entries = container.getClasspathEntries(); - for (IClasspathEntry cpe : entries) { - processCPE(cpe, javaProject, wsRoot, projects, jarFiles, includeJarFiles); - } - } - } catch (JavaModelException jme) { - // can't resolve the container? ignore it. - AdtPlugin.log(jme, "Failed to resolve ClasspathContainer: %s", entry.getPath()); - } - } - } - - private static final class CPEFile extends File { - private static final long serialVersionUID = 1L; - - private final IClasspathEntry mClasspathEntry; - - public CPEFile(String pathname, IClasspathEntry classpathEntry) { - super(pathname); - mClasspathEntry = classpathEntry; - } - - public CPEFile(File file, IClasspathEntry classpathEntry) { - super(file.getAbsolutePath()); - mClasspathEntry = classpathEntry; - } - - public IClasspathEntry getClasspathEntry() { - return mClasspathEntry; - } - } - - private static void handleClasspathLibrary(IClasspathEntry e, IWorkspaceRoot wsRoot, - Set<File> jarFiles) { - // get the IPath - IPath path = e.getPath(); - - IResource resource = wsRoot.findMember(path); - - if (SdkConstants.EXT_JAR.equalsIgnoreCase(path.getFileExtension())) { - // case of a jar file (which could be relative to the workspace or a full path) - if (resource != null && resource.exists() && - resource.getType() == IResource.FILE) { - jarFiles.add(new CPEFile(resource.getLocation().toFile(), e)); - } else { - // if the jar path doesn't match a workspace resource, - // then we get an OSString and check if this links to a valid file. - String osFullPath = path.toOSString(); - - File f = new CPEFile(osFullPath, e); - if (f.isFile()) { - jarFiles.add(f); - } - } - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectChooserHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectChooserHelper.java deleted file mode 100644 index 9de8ad06e..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectChooserHelper.java +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Copyright (C) 2008 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.project; - -import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper.IProjectFilter; -import com.android.ide.eclipse.adt.internal.sdk.ProjectState; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.jdt.core.IJavaModel; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.ui.JavaElementLabelProvider; -import org.eclipse.jface.viewers.ILabelProvider; -import org.eclipse.jface.window.Window; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.ui.dialogs.ElementListSelectionDialog; - -/** - * Helper class to deal with displaying a project choosing dialog that lists only the - * projects with the Android nature. - */ -public class ProjectChooserHelper { - - private final Shell mParentShell; - private final IProjectChooserFilter mFilter; - - /** - * List of current android projects. Since the dialog is modal, we'll just get - * the list once on-demand. - */ - private IJavaProject[] mAndroidProjects; - - /** - * Interface to filter out some project displayed by {@link ProjectChooserHelper}. - * - * @see IProjectFilter - */ - public interface IProjectChooserFilter extends IProjectFilter { - /** - * Whether the Project Chooser can compute the project list once and cache the result. - * </p>If false the project list is recomputed every time the dialog is opened. - */ - boolean useCache(); - } - - /** - * An implementation of {@link IProjectChooserFilter} that only displays non-library projects. - */ - public final static class NonLibraryProjectOnlyFilter implements IProjectChooserFilter { - @Override - public boolean accept(IProject project) { - ProjectState state = Sdk.getProjectState(project); - if (state != null) { - return state.isLibrary() == false; - } - - return false; - } - - @Override - public boolean useCache() { - return true; - } - } - - /** - * An implementation of {@link IProjectChooserFilter} that only displays library projects. - */ - public final static class LibraryProjectOnlyFilter implements IProjectChooserFilter { - @Override - public boolean accept(IProject project) { - ProjectState state = Sdk.getProjectState(project); - if (state != null ) { - return state.isLibrary(); - } - - return false; - } - - @Override - public boolean useCache() { - return true; - } - } - - /** - * Creates a new project chooser. - * @param parentShell the parent {@link Shell} for the dialog. - * @param filter a filter to only accept certain projects. Can be null. - */ - public ProjectChooserHelper(Shell parentShell, IProjectChooserFilter filter) { - mParentShell = parentShell; - mFilter = filter; - } - - /** - * Displays a project chooser dialog which lists all available projects with the Android nature. - * <p/> - * The list of project is built from Android flagged projects currently opened in the workspace. - * - * @param projectName If non null and not empty, represents the name of an Android project - * that will be selected by default. - * @param message Message for the dialog box. Can be null in which case a default message - * is displayed. - * @return the project chosen by the user in the dialog, or null if the dialog was canceled. - */ - public IJavaProject chooseJavaProject(String projectName, String message) { - ILabelProvider labelProvider = new JavaElementLabelProvider( - JavaElementLabelProvider.SHOW_DEFAULT); - ElementListSelectionDialog dialog = new ElementListSelectionDialog( - mParentShell, labelProvider); - dialog.setTitle("Project Selection"); - if (message == null) { - message = "Please select a project"; - } - dialog.setMessage(message); - - IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); - IJavaModel javaModel = JavaCore.create(workspaceRoot); - - // set the elements in the dialog. These are opened android projects. - dialog.setElements(getAndroidProjects(javaModel)); - - // look for the project matching the given project name - IJavaProject javaProject = null; - if (projectName != null && projectName.length() > 0) { - javaProject = javaModel.getJavaProject(projectName); - } - - // if we found it, we set the initial selection in the dialog to this one. - if (javaProject != null) { - dialog.setInitialSelections(new Object[] { javaProject }); - } - - // open the dialog and return the object selected if OK was clicked, or null otherwise - if (dialog.open() == Window.OK) { - return (IJavaProject) dialog.getFirstResult(); - } - return null; - } - - /** - * Returns the list of Android projects. - * <p/> - * Because this list can be time consuming, this class caches the list of project. - * It is recommended to call this method instead of - * {@link BaseProjectHelper#getAndroidProjects()}. - * - * @param javaModel the java model. Can be null. - */ - public IJavaProject[] getAndroidProjects(IJavaModel javaModel) { - // recompute only if we don't have the projects already or the filter is dynamic - // and prevent usage of a cache. - if (mAndroidProjects == null || (mFilter != null && mFilter.useCache() == false)) { - if (javaModel == null) { - mAndroidProjects = BaseProjectHelper.getAndroidProjects(mFilter); - } else { - mAndroidProjects = BaseProjectHelper.getAndroidProjects(javaModel, mFilter); - } - } - - return mAndroidProjects; - } - - /** - * Helper method to get the Android project with the given name - * - * @param projectName the name of the project to find - * @return the {@link IProject} for the Android project. <code>null</code> if not found. - */ - public IProject getAndroidProject(String projectName) { - IProject iproject = null; - IJavaProject[] javaProjects = getAndroidProjects(null); - if (javaProjects != null) { - for (IJavaProject javaProject : javaProjects) { - if (javaProject.getElementName().equals(projectName)) { - iproject = javaProject.getProject(); - break; - } - } - } - return iproject; - } - - /** - * A selector combo for showing the currently selected project and for - * changing the selection - */ - public static class ProjectCombo extends Combo implements SelectionListener { - /** Currently chosen project, or null when no project has been initialized or selected */ - private IProject mProject; - private IJavaProject[] mAvailableProjects; - - /** - * Creates a new project selector combo - * - * @param helper associated {@link ProjectChooserHelper} for looking up - * projects - * @param parent parent composite to add the combo to - * @param initialProject the initial project to select, or null (which - * will show a "Please Choose Project..." label instead.) - */ - public ProjectCombo(ProjectChooserHelper helper, Composite parent, - IProject initialProject) { - super(parent, SWT.BORDER | SWT.FLAT | SWT.READ_ONLY); - mProject = initialProject; - - mAvailableProjects = helper.getAndroidProjects(null); - String[] items = new String[mAvailableProjects.length + 1]; - items[0] = "--- Choose Project ---"; - - ILabelProvider labelProvider = new JavaElementLabelProvider( - JavaElementLabelProvider.SHOW_DEFAULT); - int selectionIndex = 0; - for (int i = 0, n = mAvailableProjects.length; i < n; i++) { - IProject project = mAvailableProjects[i].getProject(); - items[i + 1] = labelProvider.getText(project); - if (project == initialProject) { - selectionIndex = i + 1; - } - } - setItems(items); - select(selectionIndex); - - addSelectionListener(this); - } - - /** - * Returns the project selected by this chooser (or the initial project - * passed to the constructor if the user did not change it) - * - * @return the selected project - */ - public IProject getSelectedProject() { - return mProject; - } - - /** - * Sets the project selected by this chooser - * - * @param project the selected project - */ - public void setSelectedProject(IProject project) { - mProject = project; - - int selectionIndex = 0; - for (int i = 0, n = mAvailableProjects.length; i < n; i++) { - if (project == mAvailableProjects[i].getProject()) { - selectionIndex = i + 1; // +1: Slot 0 is reserved for "Choose Project" - select(selectionIndex); - break; - } - } - } - - /** - * Click handler for the button: Open the {@link ProjectChooserHelper} - * dialog for selecting a new project. - */ - @Override - public void widgetSelected(SelectionEvent e) { - int selectionIndex = getSelectionIndex(); - if (selectionIndex > 0 && mAvailableProjects != null - && selectionIndex <= mAvailableProjects.length) { - // selection index 0 is "Choose Project", all other projects are offset - // by 1 from the selection index - mProject = mAvailableProjects[selectionIndex - 1].getProject(); - } else { - mProject = null; - } - } - - @Override - public void widgetDefaultSelected(SelectionEvent e) { - } - - @Override - protected void checkSubclass() { - // Disable the check that prevents subclassing of SWT components - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectHelper.java deleted file mode 100644 index a32b4ca8b..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectHelper.java +++ /dev/null @@ -1,1153 +0,0 @@ -/* - * 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.project; - -import static com.android.ide.eclipse.adt.AdtConstants.COMPILER_COMPLIANCE_PREFERRED; - -import com.android.SdkConstants; -import com.android.annotations.NonNull; -import com.android.ide.common.xml.ManifestData; -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.build.builders.PostCompilerBuilder; -import com.android.ide.eclipse.adt.internal.build.builders.PreCompilerBuilder; -import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; -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.ICommand; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IMarker; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IProjectDescription; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IWorkspace; -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.NullProgressMonitor; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.QualifiedName; -import org.eclipse.jdt.core.IClasspathEntry; -import org.eclipse.jdt.core.IJavaModel; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jdt.internal.corext.util.JavaModelUtil; -import org.eclipse.jdt.launching.IVMInstall; -import org.eclipse.jdt.launching.IVMInstall2; -import org.eclipse.jdt.launching.IVMInstallType; -import org.eclipse.jdt.launching.JavaRuntime; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; - -/** - * Utility class to manipulate Project parameters/properties. - */ -public final class ProjectHelper { - public final static int COMPILER_COMPLIANCE_OK = 0; - public final static int COMPILER_COMPLIANCE_LEVEL = 1; - public final static int COMPILER_COMPLIANCE_SOURCE = 2; - public final static int COMPILER_COMPLIANCE_CODEGEN_TARGET = 3; - - /** - * Adds the given ClasspathEntry object to the class path entries. - * This method does not check whether the entry is already defined in the project. - * - * @param entries The class path entries to read. A copy will be returned. - * @param newEntry The new class path entry to add. - * @return A new class path entries array. - */ - public static IClasspathEntry[] addEntryToClasspath( - IClasspathEntry[] entries, IClasspathEntry newEntry) { - int n = entries.length; - IClasspathEntry[] newEntries = new IClasspathEntry[n + 1]; - System.arraycopy(entries, 0, newEntries, 0, n); - newEntries[n] = newEntry; - return newEntries; - } - - /** - * Replaces the given ClasspathEntry in the classpath entries. - * - * If the classpath does not yet exists (Check is based on entry path), then it is added. - * - * @param entries The class path entries to read. The same array (replace) or a copy (add) - * will be returned. - * @param newEntry The new class path entry to add. - * @return The same array (replace) or a copy (add) will be returned. - * - * @see IClasspathEntry#getPath() - */ - public static IClasspathEntry[] replaceEntryInClasspath( - IClasspathEntry[] entries, IClasspathEntry newEntry) { - - IPath path = newEntry.getPath(); - for (int i = 0, count = entries.length; i < count ; i++) { - if (path.equals(entries[i].getPath())) { - entries[i] = newEntry; - return entries; - } - } - - return addEntryToClasspath(entries, newEntry); - } - - /** - * Adds the corresponding source folder to the project's class path entries. - * This method does not check whether the entry is already defined in the project. - * - * @param javaProject The java project of which path entries to update. - * @param newEntry The new class path entry to add. - * @throws JavaModelException - */ - public static void addEntryToClasspath(IJavaProject javaProject, IClasspathEntry newEntry) - throws JavaModelException { - - IClasspathEntry[] entries = javaProject.getRawClasspath(); - entries = addEntryToClasspath(entries, newEntry); - javaProject.setRawClasspath(entries, new NullProgressMonitor()); - } - - /** - * Checks whether the given class path entry is already defined in the project. - * - * @param javaProject The java project of which path entries to check. - * @param newEntry The parent source folder to remove. - * @return True if the class path entry is already defined. - * @throws JavaModelException - */ - public static boolean isEntryInClasspath(IJavaProject javaProject, IClasspathEntry newEntry) - throws JavaModelException { - - IClasspathEntry[] entries = javaProject.getRawClasspath(); - for (IClasspathEntry entry : entries) { - if (entry.equals(newEntry)) { - return true; - } - } - return false; - } - - /** - * Remove a classpath entry from the array. - * @param entries The class path entries to read. A copy will be returned - * @param index The index to remove. - * @return A new class path entries array. - */ - public static IClasspathEntry[] removeEntryFromClasspath( - IClasspathEntry[] entries, int index) { - int n = entries.length; - IClasspathEntry[] newEntries = new IClasspathEntry[n-1]; - - // copy the entries before index - System.arraycopy(entries, 0, newEntries, 0, index); - - // copy the entries after index - System.arraycopy(entries, index + 1, newEntries, index, - entries.length - index - 1); - - return newEntries; - } - - /** - * Converts a OS specific path into a path valid for the java doc location - * attributes of a project. - * @param javaDocOSLocation The OS specific path. - * @return a valid path for the java doc location. - */ - public static String getJavaDocPath(String javaDocOSLocation) { - // first thing we do is convert the \ into / - String javaDoc = javaDocOSLocation.replaceAll("\\\\", //$NON-NLS-1$ - AdtConstants.WS_SEP); - - // then we add file: at the beginning for unix path, and file:/ for non - // unix path - if (javaDoc.startsWith(AdtConstants.WS_SEP)) { - return "file:" + javaDoc; //$NON-NLS-1$ - } - - return "file:/" + javaDoc; //$NON-NLS-1$ - } - - /** - * Look for a specific classpath entry by full path and return its index. - * @param entries The entry array to search in. - * @param entryPath The OS specific path of the entry. - * @param entryKind The kind of the entry. Accepted values are 0 - * (no filter), IClasspathEntry.CPE_LIBRARY, IClasspathEntry.CPE_PROJECT, - * IClasspathEntry.CPE_SOURCE, IClasspathEntry.CPE_VARIABLE, - * and IClasspathEntry.CPE_CONTAINER - * @return the index of the found classpath entry or -1. - */ - public static int findClasspathEntryByPath(IClasspathEntry[] entries, - String entryPath, int entryKind) { - for (int i = 0 ; i < entries.length ; i++) { - IClasspathEntry entry = entries[i]; - - int kind = entry.getEntryKind(); - - if (kind == entryKind || entryKind == 0) { - // get the path - IPath path = entry.getPath(); - - String osPathString = path.toOSString(); - if (osPathString.equals(entryPath)) { - return i; - } - } - } - - // not found, return bad index. - return -1; - } - - /** - * Look for a specific classpath entry for file name only and return its - * index. - * @param entries The entry array to search in. - * @param entryName The filename of the entry. - * @param entryKind The kind of the entry. Accepted values are 0 - * (no filter), IClasspathEntry.CPE_LIBRARY, IClasspathEntry.CPE_PROJECT, - * IClasspathEntry.CPE_SOURCE, IClasspathEntry.CPE_VARIABLE, - * and IClasspathEntry.CPE_CONTAINER - * @param startIndex Index where to start the search - * @return the index of the found classpath entry or -1. - */ - public static int findClasspathEntryByName(IClasspathEntry[] entries, - String entryName, int entryKind, int startIndex) { - if (startIndex < 0) { - startIndex = 0; - } - for (int i = startIndex ; i < entries.length ; i++) { - IClasspathEntry entry = entries[i]; - - int kind = entry.getEntryKind(); - - if (kind == entryKind || entryKind == 0) { - // get the path - IPath path = entry.getPath(); - String name = path.segment(path.segmentCount()-1); - - if (name.equals(entryName)) { - return i; - } - } - } - - // not found, return bad index. - return -1; - } - - public static boolean updateProject(IJavaProject project) { - return updateProjects(new IJavaProject[] { project}); - } - - /** - * Update the android-specific projects's classpath containers. - * @param projects the projects to update - * @return - */ - public static boolean updateProjects(IJavaProject[] projects) { - boolean r = AndroidClasspathContainerInitializer.updateProjects(projects); - if (r) { - return LibraryClasspathContainerInitializer.updateProjects(projects); - } - return false; - } - - /** - * Fix the project. This checks the SDK location. - * @param project The project to fix. - * @throws JavaModelException - */ - public static void fixProject(IProject project) throws JavaModelException { - if (AdtPlugin.getOsSdkFolder().length() == 0) { - AdtPlugin.printToConsole(project, "Unknown SDK Location, project not fixed."); - return; - } - - // get a java project - IJavaProject javaProject = JavaCore.create(project); - fixProjectClasspathEntries(javaProject); - } - - /** - * Fix the project classpath entries. The method ensures that: - * <ul> - * <li>The project does not reference any old android.zip/android.jar archive.</li> - * <li>The project does not use its output folder as a sourc folder.</li> - * <li>The project does not reference a desktop JRE</li> - * <li>The project references the AndroidClasspathContainer. - * </ul> - * @param javaProject The project to fix. - * @throws JavaModelException - */ - public static void fixProjectClasspathEntries(IJavaProject javaProject) - throws JavaModelException { - - // get the project classpath - IClasspathEntry[] entries = javaProject.getRawClasspath(); - IClasspathEntry[] oldEntries = entries; - boolean forceRewriteOfCPE = false; - - // check if the JRE is set as library - int jreIndex = ProjectHelper.findClasspathEntryByPath(entries, JavaRuntime.JRE_CONTAINER, - IClasspathEntry.CPE_CONTAINER); - if (jreIndex != -1) { - // the project has a JRE included, we remove it - entries = ProjectHelper.removeEntryFromClasspath(entries, jreIndex); - } - - // get the output folder - IPath outputFolder = javaProject.getOutputLocation(); - - boolean foundFrameworkContainer = false; - IClasspathEntry foundLibrariesContainer = null; - IClasspathEntry foundDependenciesContainer = null; - - for (int i = 0 ; i < entries.length ;) { - // get the entry and kind - IClasspathEntry entry = entries[i]; - int kind = entry.getEntryKind(); - - if (kind == IClasspathEntry.CPE_SOURCE) { - IPath path = entry.getPath(); - - if (path.equals(outputFolder)) { - entries = ProjectHelper.removeEntryFromClasspath(entries, i); - - // continue, to skip the i++; - continue; - } - } else if (kind == IClasspathEntry.CPE_CONTAINER) { - String path = entry.getPath().toString(); - if (AdtConstants.CONTAINER_FRAMEWORK.equals(path)) { - foundFrameworkContainer = true; - } else if (AdtConstants.CONTAINER_PRIVATE_LIBRARIES.equals(path)) { - foundLibrariesContainer = entry; - } else if (AdtConstants.CONTAINER_DEPENDENCIES.equals(path)) { - foundDependenciesContainer = entry; - } - } - - i++; - } - - // look to see if we have the m2eclipse nature - boolean m2eNature = false; - try { - m2eNature = javaProject.getProject().hasNature("org.eclipse.m2e.core.maven2Nature"); - } catch (CoreException e) { - AdtPlugin.log(e, "Failed to query project %s for m2e nature", - javaProject.getProject().getName()); - } - - - // if the framework container is not there, we add it - if (!foundFrameworkContainer) { - // add the android container to the array - entries = ProjectHelper.addEntryToClasspath(entries, - JavaCore.newContainerEntry(new Path(AdtConstants.CONTAINER_FRAMEWORK))); - } - - // same thing for the library container - if (foundLibrariesContainer == null) { - // add the exported libraries android container to the array - entries = ProjectHelper.addEntryToClasspath(entries, - JavaCore.newContainerEntry( - new Path(AdtConstants.CONTAINER_PRIVATE_LIBRARIES), true)); - } else if (!m2eNature && !foundLibrariesContainer.isExported()) { - // the container is present but it's not exported and since there's no m2e nature - // we do want it to be exported. - // keep all the other parameters the same. - entries = ProjectHelper.replaceEntryInClasspath(entries, - JavaCore.newContainerEntry( - new Path(AdtConstants.CONTAINER_PRIVATE_LIBRARIES), - foundLibrariesContainer.getAccessRules(), - foundLibrariesContainer.getExtraAttributes(), - true)); - forceRewriteOfCPE = true; - } - - // same thing for the dependencies container - if (foundDependenciesContainer == null) { - // add the android dependencies container to the array - entries = ProjectHelper.addEntryToClasspath(entries, - JavaCore.newContainerEntry( - new Path(AdtConstants.CONTAINER_DEPENDENCIES), true)); - } else if (!m2eNature && !foundDependenciesContainer.isExported()) { - // the container is present but it's not exported and since there's no m2e nature - // we do want it to be exported. - // keep all the other parameters the same. - entries = ProjectHelper.replaceEntryInClasspath(entries, - JavaCore.newContainerEntry( - new Path(AdtConstants.CONTAINER_DEPENDENCIES), - foundDependenciesContainer.getAccessRules(), - foundDependenciesContainer.getExtraAttributes(), - true)); - forceRewriteOfCPE = true; - } - - // set the new list of entries to the project - if (entries != oldEntries || forceRewriteOfCPE) { - javaProject.setRawClasspath(entries, new NullProgressMonitor()); - } - - // If needed, check and fix compiler compliance and source compatibility - ProjectHelper.checkAndFixCompilerCompliance(javaProject); - } - - - /** - * Checks the project compiler compliance level is supported. - * @param javaProject The project to check - * @return A pair with the first integer being an error code, and the second value - * being the invalid value found or null. The error code can be: <ul> - * <li><code>COMPILER_COMPLIANCE_OK</code> if the project is properly configured</li> - * <li><code>COMPILER_COMPLIANCE_LEVEL</code> for unsupported compiler level</li> - * <li><code>COMPILER_COMPLIANCE_SOURCE</code> for unsupported source compatibility</li> - * <li><code>COMPILER_COMPLIANCE_CODEGEN_TARGET</code> for unsupported .class format</li> - * </ul> - */ - public static final Pair<Integer, String> checkCompilerCompliance(IJavaProject javaProject) { - // get the project compliance level option - String compliance = javaProject.getOption(JavaCore.COMPILER_COMPLIANCE, true); - - // check it against a list of valid compliance level strings. - if (!checkCompliance(javaProject, compliance)) { - // if we didn't find the proper compliance level, we return an error - return Pair.of(COMPILER_COMPLIANCE_LEVEL, compliance); - } - - // otherwise we check source compatibility - String source = javaProject.getOption(JavaCore.COMPILER_SOURCE, true); - - // check it against a list of valid compliance level strings. - if (!checkCompliance(javaProject, source)) { - // if we didn't find the proper compliance level, we return an error - return Pair.of(COMPILER_COMPLIANCE_SOURCE, source); - } - - // otherwise check codegen level - String codeGen = javaProject.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true); - - // check it against a list of valid compliance level strings. - if (!checkCompliance(javaProject, codeGen)) { - // if we didn't find the proper compliance level, we return an error - return Pair.of(COMPILER_COMPLIANCE_CODEGEN_TARGET, codeGen); - } - - return Pair.of(COMPILER_COMPLIANCE_OK, null); - } - - /** - * Checks the project compiler compliance level is supported. - * @param project The project to check - * @return A pair with the first integer being an error code, and the second value - * being the invalid value found or null. The error code can be: <ul> - * <li><code>COMPILER_COMPLIANCE_OK</code> if the project is properly configured</li> - * <li><code>COMPILER_COMPLIANCE_LEVEL</code> for unsupported compiler level</li> - * <li><code>COMPILER_COMPLIANCE_SOURCE</code> for unsupported source compatibility</li> - * <li><code>COMPILER_COMPLIANCE_CODEGEN_TARGET</code> for unsupported .class format</li> - * </ul> - */ - public static final Pair<Integer, String> checkCompilerCompliance(IProject project) { - // get the java project from the IProject resource object - IJavaProject javaProject = JavaCore.create(project); - - // check and return the result. - return checkCompilerCompliance(javaProject); - } - - - /** - * Checks, and fixes if needed, the compiler compliance level, and the source compatibility - * level - * @param project The project to check and fix. - */ - public static final void checkAndFixCompilerCompliance(IProject project) { - // FIXME This method is never used. Shall we just removed it? - // {@link #checkAndFixCompilerCompliance(IJavaProject)} is used instead. - - // get the java project from the IProject resource object - IJavaProject javaProject = JavaCore.create(project); - - // Now we check the compiler compliance level and make sure it is valid - checkAndFixCompilerCompliance(javaProject); - } - - /** - * Checks, and fixes if needed, the compiler compliance level, and the source compatibility - * level - * @param javaProject The Java project to check and fix. - */ - public static final void checkAndFixCompilerCompliance(IJavaProject javaProject) { - Pair<Integer, String> result = checkCompilerCompliance(javaProject); - if (result.getFirst().intValue() != COMPILER_COMPLIANCE_OK) { - // setup the preferred compiler compliance level. - javaProject.setOption(JavaCore.COMPILER_COMPLIANCE, - AdtConstants.COMPILER_COMPLIANCE_PREFERRED); - javaProject.setOption(JavaCore.COMPILER_SOURCE, - AdtConstants.COMPILER_COMPLIANCE_PREFERRED); - javaProject.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, - AdtConstants.COMPILER_COMPLIANCE_PREFERRED); - - // clean the project to make sure we recompile - try { - javaProject.getProject().build(IncrementalProjectBuilder.CLEAN_BUILD, - new NullProgressMonitor()); - } catch (CoreException e) { - AdtPlugin.printErrorToConsole(javaProject.getProject(), - "Project compiler settings changed. Clean your project."); - } - } - } - - /** - * Makes the given project use JDK 6 (or more specifically, - * {@link AdtConstants#COMPILER_COMPLIANCE_PREFERRED} as the compilation - * target, regardless of what the default IDE JDK level is, provided a JRE - * of the given level is installed. - * - * @param javaProject the Java project - * @throws CoreException if the IDE throws an exception setting the compiler - * level - */ - @SuppressWarnings("restriction") // JDT API for setting compliance options - public static void enforcePreferredCompilerCompliance(@NonNull IJavaProject javaProject) - throws CoreException { - String compliance = javaProject.getOption(JavaCore.COMPILER_COMPLIANCE, true); - if (compliance == null || - JavaModelUtil.isVersionLessThan(compliance, COMPILER_COMPLIANCE_PREFERRED)) { - IVMInstallType[] types = JavaRuntime.getVMInstallTypes(); - for (int i = 0; i < types.length; i++) { - IVMInstallType type = types[i]; - IVMInstall[] installs = type.getVMInstalls(); - for (int j = 0; j < installs.length; j++) { - IVMInstall install = installs[j]; - if (install instanceof IVMInstall2) { - IVMInstall2 install2 = (IVMInstall2) install; - // Java version can be 1.6.0, and preferred is 1.6 - if (install2.getJavaVersion().startsWith(COMPILER_COMPLIANCE_PREFERRED)) { - Map<String, String> options = javaProject.getOptions(false); - JavaCore.setComplianceOptions(COMPILER_COMPLIANCE_PREFERRED, options); - JavaModelUtil.setDefaultClassfileOptions(options, - COMPILER_COMPLIANCE_PREFERRED); - javaProject.setOptions(options); - return; - } - } - } - } - } - } - - /** - * Returns a {@link IProject} by its running application name, as it returned by the AVD. - * <p/> - * <var>applicationName</var> will in most case be the package declared in the manifest, but - * can, in some cases, be a custom process name declared in the manifest, in the - * <code>application</code>, <code>activity</code>, <code>receiver</code>, or - * <code>service</code> nodes. - * @param applicationName The application name. - * @return a project or <code>null</code> if no matching project were found. - */ - public static IProject findAndroidProjectByAppName(String applicationName) { - // Get the list of project for the current workspace - IWorkspace workspace = ResourcesPlugin.getWorkspace(); - IProject[] projects = workspace.getRoot().getProjects(); - - // look for a project that matches the packageName of the app - // we're trying to debug - for (IProject p : projects) { - if (p.isOpen()) { - try { - if (p.hasNature(AdtConstants.NATURE_DEFAULT) == false) { - // ignore non android projects - continue; - } - } catch (CoreException e) { - // failed to get the nature? skip project. - continue; - } - - // check that there is indeed a manifest file. - IFile manifestFile = getManifest(p); - if (manifestFile == null) { - // no file? skip this project. - continue; - } - - ManifestData data = AndroidManifestHelper.parseForData(manifestFile); - if (data == null) { - // skip this project. - continue; - } - - String manifestPackage = data.getPackage(); - - if (manifestPackage != null && manifestPackage.equals(applicationName)) { - // this is the project we were looking for! - return p; - } else { - // if the package and application name don't match, - // we look for other possible process names declared in the manifest. - String[] processes = data.getProcesses(); - for (String process : processes) { - if (process.equals(applicationName)) { - return p; - } - } - } - } - } - - return null; - - } - - public static void fixProjectNatureOrder(IProject project) throws CoreException { - IProjectDescription description = project.getDescription(); - String[] natures = description.getNatureIds(); - - // if the android nature is not the first one, we reorder them - if (AdtConstants.NATURE_DEFAULT.equals(natures[0]) == false) { - // look for the index - for (int i = 0 ; i < natures.length ; i++) { - if (AdtConstants.NATURE_DEFAULT.equals(natures[i])) { - // if we try to just reorder the array in one pass, this doesn't do - // anything. I guess JDT check that we are actually adding/removing nature. - // So, first we'll remove the android nature, and then add it back. - - // remove the android nature - removeNature(project, AdtConstants.NATURE_DEFAULT); - - // now add it back at the first index. - description = project.getDescription(); - natures = description.getNatureIds(); - - String[] newNatures = new String[natures.length + 1]; - - // first one is android - newNatures[0] = AdtConstants.NATURE_DEFAULT; - - // next the rest that was before the android nature - System.arraycopy(natures, 0, newNatures, 1, natures.length); - - // set the new natures - description.setNatureIds(newNatures); - project.setDescription(description, null); - - // and stop - break; - } - } - } - } - - - /** - * Removes a specific nature from a project. - * @param project The project to remove the nature from. - * @param nature The nature id to remove. - * @throws CoreException - */ - public static void removeNature(IProject project, String nature) throws CoreException { - IProjectDescription description = project.getDescription(); - String[] natures = description.getNatureIds(); - - // check if the project already has the android nature. - for (int i = 0; i < natures.length; ++i) { - if (nature.equals(natures[i])) { - String[] newNatures = new String[natures.length - 1]; - if (i > 0) { - System.arraycopy(natures, 0, newNatures, 0, i); - } - System.arraycopy(natures, i + 1, newNatures, i, natures.length - i - 1); - description.setNatureIds(newNatures); - project.setDescription(description, null); - - return; - } - } - - } - - /** - * Returns if the project has error level markers. - * @param includeReferencedProjects flag to also test the referenced projects. - * @throws CoreException - */ - public static boolean hasError(IProject project, boolean includeReferencedProjects) - throws CoreException { - IMarker[] markers = project.findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE); - if (markers != null && markers.length > 0) { - // the project has marker(s). even though they are "problem" we - // don't know their severity. so we loop on them and figure if they - // are warnings or errors - for (IMarker m : markers) { - int s = m.getAttribute(IMarker.SEVERITY, -1); - if (s == IMarker.SEVERITY_ERROR) { - return true; - } - } - } - - // test the referenced projects if needed. - if (includeReferencedProjects) { - List<IProject> projects = getReferencedProjects(project); - - for (IProject p : projects) { - if (hasError(p, false)) { - return true; - } - } - } - - return false; - } - - /** - * Saves a String property into the persistent storage of a resource. - * @param resource The resource into which the string value is saved. - * @param propertyName the name of the property. The id of the plug-in is added to this string. - * @param value the value to save - * @return true if the save succeeded. - */ - public static boolean saveStringProperty(IResource resource, String propertyName, - String value) { - QualifiedName qname = new QualifiedName(AdtPlugin.PLUGIN_ID, propertyName); - - try { - resource.setPersistentProperty(qname, value); - } catch (CoreException e) { - return false; - } - - return true; - } - - /** - * Loads a String property from the persistent storage of a resource. - * @param resource The resource from which the string value is loaded. - * @param propertyName the name of the property. The id of the plug-in is added to this string. - * @return the property value or null if it was not found. - */ - public static String loadStringProperty(IResource resource, String propertyName) { - QualifiedName qname = new QualifiedName(AdtPlugin.PLUGIN_ID, propertyName); - - try { - String value = resource.getPersistentProperty(qname); - return value; - } catch (CoreException e) { - return null; - } - } - - /** - * Saves a property into the persistent storage of a resource. - * @param resource The resource into which the boolean value is saved. - * @param propertyName the name of the property. The id of the plug-in is added to this string. - * @param value the value to save - * @return true if the save succeeded. - */ - public static boolean saveBooleanProperty(IResource resource, String propertyName, - boolean value) { - return saveStringProperty(resource, propertyName, Boolean.toString(value)); - } - - /** - * Loads a boolean property from the persistent storage of a resource. - * @param resource The resource from which the boolean value is loaded. - * @param propertyName the name of the property. The id of the plug-in is added to this string. - * @param defaultValue The default value to return if the property was not found. - * @return the property value or the default value if the property was not found. - */ - public static boolean loadBooleanProperty(IResource resource, String propertyName, - boolean defaultValue) { - String value = loadStringProperty(resource, propertyName); - if (value != null) { - return Boolean.parseBoolean(value); - } - - return defaultValue; - } - - public static Boolean loadBooleanProperty(IResource resource, String propertyName) { - String value = loadStringProperty(resource, propertyName); - if (value != null) { - return Boolean.valueOf(value); - } - - return null; - } - - /** - * Saves the path of a resource into the persistent storage of a resource. - * @param resource The resource into which the resource path is saved. - * @param propertyName the name of the property. The id of the plug-in is added to this string. - * @param value The resource to save. It's its path that is actually stored. If null, an - * empty string is stored. - * @return true if the save succeeded - */ - public static boolean saveResourceProperty(IResource resource, String propertyName, - IResource value) { - if (value != null) { - IPath iPath = value.getFullPath(); - return saveStringProperty(resource, propertyName, iPath.toString()); - } - - return saveStringProperty(resource, propertyName, ""); //$NON-NLS-1$ - } - - /** - * Loads the path of a resource from the persistent storage of a resource, and returns the - * corresponding IResource object. - * @param resource The resource from which the resource path is loaded. - * @param propertyName the name of the property. The id of the plug-in is added to this string. - * @return The corresponding IResource object (or children interface) or null - */ - public static IResource loadResourceProperty(IResource resource, String propertyName) { - String value = loadStringProperty(resource, propertyName); - - if (value != null && value.length() > 0) { - return ResourcesPlugin.getWorkspace().getRoot().findMember(new Path(value)); - } - - return null; - } - - /** - * Returns the list of referenced project that are opened and Java projects. - * @param project - * @return a new list object containing the opened referenced java project. - * @throws CoreException - */ - public static List<IProject> getReferencedProjects(IProject project) throws CoreException { - IProject[] projects = project.getReferencedProjects(); - - ArrayList<IProject> list = new ArrayList<IProject>(); - - for (IProject p : projects) { - if (p.isOpen() && p.hasNature(JavaCore.NATURE_ID)) { - list.add(p); - } - } - - return list; - } - - - /** - * Checks a Java project compiler level option against a list of supported versions. - * @param optionValue the Compiler level option. - * @return true if the option value is supported. - */ - private static boolean checkCompliance(@NonNull IJavaProject project, String optionValue) { - for (String s : AdtConstants.COMPILER_COMPLIANCE) { - if (s != null && s.equals(optionValue)) { - return true; - } - } - - if (JavaCore.VERSION_1_7.equals(optionValue)) { - // Requires API 19 and buildTools 19 - Sdk currentSdk = Sdk.getCurrent(); - if (currentSdk != null) { - IProject p = project.getProject(); - IAndroidTarget target = currentSdk.getTarget(p); - if (target == null || target.getVersion().getApiLevel() < 19) { - return false; - } - - ProjectState projectState = Sdk.getProjectState(p); - if (projectState != null) { - BuildToolInfo buildToolInfo = projectState.getBuildToolInfo(); - if (buildToolInfo == null) { - buildToolInfo = currentSdk.getLatestBuildTool(); - } - if (buildToolInfo == null || buildToolInfo.getRevision().getMajor() < 19) { - return false; - } - } - - return true; - } - } - - return false; - } - - /** - * Returns the apk filename for the given project - * @param project The project. - * @param config An optional config name. Can be null. - */ - public static String getApkFilename(IProject project, String config) { - if (config != null) { - return project.getName() + "-" + config + SdkConstants.DOT_ANDROID_PACKAGE; //$NON-NLS-1$ - } - - return project.getName() + SdkConstants.DOT_ANDROID_PACKAGE; - } - - /** - * Find the list of projects on which this JavaProject is dependent on at the compilation level. - * - * @param javaProject Java project that we are looking for the dependencies. - * @return A list of Java projects for which javaProject depend on. - * @throws JavaModelException - */ - public static List<IJavaProject> getAndroidProjectDependencies(IJavaProject javaProject) - throws JavaModelException { - String[] requiredProjectNames = javaProject.getRequiredProjectNames(); - - // Go from java project name to JavaProject name - IJavaModel javaModel = javaProject.getJavaModel(); - - // loop through all dependent projects and keep only those that are Android projects - List<IJavaProject> projectList = new ArrayList<IJavaProject>(requiredProjectNames.length); - for (String javaProjectName : requiredProjectNames) { - IJavaProject androidJavaProject = javaModel.getJavaProject(javaProjectName); - - //Verify that the project has also the Android Nature - try { - if (!androidJavaProject.getProject().hasNature(AdtConstants.NATURE_DEFAULT)) { - continue; - } - } catch (CoreException e) { - continue; - } - - projectList.add(androidJavaProject); - } - - return projectList; - } - - /** - * Returns the android package file as an IFile object for the specified - * project. - * @param project The project - * @return The android package as an IFile object or null if not found. - */ - public static IFile getApplicationPackage(IProject project) { - // get the output folder - IFolder outputLocation = BaseProjectHelper.getAndroidOutputFolder(project); - - if (outputLocation == null) { - AdtPlugin.printErrorToConsole(project, - "Failed to get the output location of the project. Check build path properties" - ); - return null; - } - - - // get the package path - String packageName = project.getName() + SdkConstants.DOT_ANDROID_PACKAGE; - IResource r = outputLocation.findMember(packageName); - - // check the package is present - if (r instanceof IFile && r.exists()) { - return (IFile)r; - } - - String msg = String.format("Could not find %1$s!", packageName); - AdtPlugin.printErrorToConsole(project, msg); - - return null; - } - - /** - * Returns an {@link IFile} object representing the manifest for the given project. - * - * @param project The project containing the manifest file. - * @return An IFile object pointing to the manifest or null if the manifest - * is missing. - */ - public static IFile getManifest(IProject project) { - IResource r = project.findMember(AdtConstants.WS_SEP - + SdkConstants.FN_ANDROID_MANIFEST_XML); - - if (r == null || r.exists() == false || (r instanceof IFile) == false) { - return null; - } - return (IFile) r; - } - - /** - * Does a full release build of the application, including the libraries. Do not build the - * package. - * - * @param project The project to be built. - * @param monitor A eclipse runtime progress monitor to be updated by the builders. - * @throws CoreException - */ - @SuppressWarnings("unchecked") - public static void compileInReleaseMode(IProject project, IProgressMonitor monitor) - throws CoreException { - compileInReleaseMode(project, true /*includeDependencies*/, monitor); - } - - /** - * Does a full release build of the application, including the libraries. Do not build the - * package. - * - * @param project The project to be built. - * @param monitor A eclipse runtime progress monitor to be updated by the builders. - * @throws CoreException - */ - @SuppressWarnings("unchecked") - private static void compileInReleaseMode(IProject project, boolean includeDependencies, - IProgressMonitor monitor) - throws CoreException { - - if (includeDependencies) { - ProjectState projectState = Sdk.getProjectState(project); - - // this gives us all the library projects, direct and indirect dependencies, - // so no need to run this method recursively. - List<IProject> libraries = projectState.getFullLibraryProjects(); - - // build dependencies in reverse order to prevent libraries being rebuilt - // due to refresh of other libraries (they would be compiled in the wrong mode). - for (int i = libraries.size() - 1 ; i >= 0 ; i--) { - IProject lib = libraries.get(i); - compileInReleaseMode(lib, false /*includeDependencies*/, monitor); - - // force refresh of the dependency. - lib.refreshLocal(IResource.DEPTH_INFINITE, monitor); - } - } - - // do a full build on all the builders to guarantee that the builders are called. - // (Eclipse does an optimization where builders are not called if there aren't any - // deltas). - - ICommand[] commands = project.getDescription().getBuildSpec(); - for (ICommand command : commands) { - String name = command.getBuilderName(); - if (PreCompilerBuilder.ID.equals(name)) { - Map newArgs = new HashMap(); - newArgs.put(PreCompilerBuilder.RELEASE_REQUESTED, ""); - if (command.getArguments() != null) { - newArgs.putAll(command.getArguments()); - } - - project.build(IncrementalProjectBuilder.FULL_BUILD, - PreCompilerBuilder.ID, newArgs, monitor); - } else if (PostCompilerBuilder.ID.equals(name)) { - if (includeDependencies == false) { - // this is a library, we need to build it! - project.build(IncrementalProjectBuilder.FULL_BUILD, name, - command.getArguments(), monitor); - } - } else { - - project.build(IncrementalProjectBuilder.FULL_BUILD, name, - command.getArguments(), monitor); - } - } - } - - /** - * Force building the project and all its dependencies. - * - * @param project the project to build - * @param kind the build kind - * @param monitor - * @throws CoreException - */ - public static void buildWithDeps(IProject project, int kind, IProgressMonitor monitor) - throws CoreException { - // Get list of projects that we depend on - ProjectState projectState = Sdk.getProjectState(project); - - // this gives us all the library projects, direct and indirect dependencies, - // so no need to run this method recursively. - List<IProject> libraries = projectState.getFullLibraryProjects(); - - // build dependencies in reverse order to prevent libraries being rebuilt - // due to refresh of other libraries (they would be compiled in the wrong mode). - for (int i = libraries.size() - 1 ; i >= 0 ; i--) { - IProject lib = libraries.get(i); - lib.build(kind, monitor); - lib.refreshLocal(IResource.DEPTH_INFINITE, monitor); - } - - project.build(kind, monitor); - } - - - /** - * Build project incrementally, including making the final packaging even if it is disabled - * by default. - * - * @param project The project to be built. - * @param monitor A eclipse runtime progress monitor to be updated by the builders. - * @throws CoreException - */ - public static void doFullIncrementalDebugBuild(IProject project, IProgressMonitor monitor) - throws CoreException { - // Get list of projects that we depend on - List<IJavaProject> androidProjectList = new ArrayList<IJavaProject>(); - try { - androidProjectList = getAndroidProjectDependencies( - BaseProjectHelper.getJavaProject(project)); - } catch (JavaModelException e) { - AdtPlugin.printErrorToConsole(project, e); - } - // Recursively build dependencies - for (IJavaProject dependency : androidProjectList) { - doFullIncrementalDebugBuild(dependency.getProject(), monitor); - } - - // Do an incremental build to pick up all the deltas - project.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, monitor); - - // If the preferences indicate not to use post compiler optimization - // then the incremental build will have done everything necessary, otherwise, - // we have to run the final builder manually (if requested). - if (AdtPrefs.getPrefs().getBuildSkipPostCompileOnFileSave()) { - // Create the map to pass to the PostC builder - Map<String, String> args = new TreeMap<String, String>(); - args.put(PostCompilerBuilder.POST_C_REQUESTED, ""); //$NON-NLS-1$ - - // call the post compiler manually, forcing FULL_BUILD otherwise Eclipse won't - // call the builder since the delta is empty. - project.build(IncrementalProjectBuilder.FULL_BUILD, - PostCompilerBuilder.ID, args, monitor); - } - - // because the post compiler builder does a delayed refresh due to - // library not picking the refresh up if it's done during the build, - // we want to force a refresh here as this call is generally asking for - // a build to use the apk right after the call. - project.refreshLocal(IResource.DEPTH_INFINITE, monitor); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/SupportLibraryHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/SupportLibraryHelper.java deleted file mode 100644 index e1819b283..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/SupportLibraryHelper.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (C) 2012 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.project; - -import static com.android.SdkConstants.FQCN_GRID_LAYOUT; -import static com.android.SdkConstants.FQCN_GRID_LAYOUT_V7; -import static com.android.SdkConstants.FQCN_SPACE; -import static com.android.SdkConstants.FQCN_SPACE_V7; - -import com.android.annotations.NonNull; -import com.android.annotations.Nullable; -import com.android.ide.eclipse.adt.AdtUtils; -import com.android.ide.eclipse.adt.internal.actions.AddSupportJarAction; -import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo; -import com.android.ide.eclipse.adt.internal.sdk.ProjectState; -import com.android.ide.eclipse.adt.internal.sdk.ProjectState.LibraryState; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; - -import org.eclipse.core.resources.IProject; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.swt.widgets.Display; - -/** - * Helper class for the Android Support Library. The support library provides - * (for example) a backport of GridLayout, which must be used as a library - * project rather than a jar library since it has resources. This class provides - * support for finding the library project, or downloading and installing it on - * demand if it does not, as well as translating tags such as - * {@code <GridLayout>} into {@code <com.android.support.v7.GridLayout>} if it - * does not. - */ -public class SupportLibraryHelper { - /** - * Returns the correct tag to use for the given view tag. This is normally - * the same as the tag itself. However, for some views which are not available - * on all platforms, this will: - * <ul> - * <li> Check if the view is available in the compatibility library, - * and if so, if the support library is not installed, will offer to - * install it via the SDK manager. - * <li> (The tool may also offer to adjust the minimum SDK of the project - * up to a level such that the given tag is supported directly, and then - * this method will return the original tag.) - * <li> Check whether the compatibility library is included in the project, and - * if not, offer to copy it into the workspace and add a library dependency. - * <li> Return the alternative tag. For example, for "GridLayout", it will - * (if the minimum SDK is less than 14) return "com.android.support.v7.GridLayout" - * instead. - * </ul> - * - * @param project the project to add the dependency into - * @param tag the tag to look up, such as "GridLayout" - * @return the tag to use in the layout, normally the same as the input tag but possibly - * an equivalent compatibility library tag instead. - */ - @NonNull - public static String getTagFor(@NonNull IProject project, @NonNull String tag) { - boolean isGridLayout = tag.equals(FQCN_GRID_LAYOUT); - boolean isSpace = tag.equals(FQCN_SPACE); - if (isGridLayout || isSpace) { - int minSdk = ManifestInfo.get(project).getMinSdkVersion(); - if (minSdk < 14) { - // See if the support library is installed in the SDK area - // See if there is a local project in the workspace providing the - // project - IProject supportProject = getSupportProjectV7(); - if (supportProject != null) { - // Make sure I have a dependency on it - ProjectState state = Sdk.getProjectState(project); - if (state != null) { - for (LibraryState library : state.getLibraries()) { - if (supportProject.equals(library.getProjectState().getProject())) { - // Found it: you have the compatibility library and have linked - // to it: use the alternative tag - return isGridLayout ? FQCN_GRID_LAYOUT_V7 : FQCN_SPACE_V7; - } - } - } - } - - // Ask user to install it - String message = String.format( - "%1$s requires API level 14 or higher, or a compatibility " - + "library for older versions.\n\n" - + " Do you want to install the compatibility library?", tag); - MessageDialog dialog = - new MessageDialog( - Display.getCurrent().getActiveShell(), - "Warning", - null, - message, - MessageDialog.QUESTION, - new String[] { - "Install", "Cancel" - }, - 1 /* default button: Cancel */); - int answer = dialog.open(); - if (answer == 0) { - if (supportProject != null) { - // Just add library dependency - if (!AddSupportJarAction.addLibraryDependency( - supportProject, - project, - true /* waitForFinish */)) { - return tag; - } - } else { - // Install library AND add dependency - if (!AddSupportJarAction.installGridLayoutLibrary( - project, - true /* waitForFinish */)) { - return tag; - } - } - - return isGridLayout ? FQCN_GRID_LAYOUT_V7 : FQCN_SPACE_V7; - } - } - } - - return tag; - } - - /** Cache for {@link #getSupportProjectV7()} */ - private static IProject sCachedProject; - - /** - * Finds and returns the support project in the workspace, if any. - * - * @return the android support library project, or null if not found - */ - @Nullable - public static IProject getSupportProjectV7() { - if (sCachedProject != null) { - if (sCachedProject.isAccessible()) { - return sCachedProject; - } else { - sCachedProject = null; - } - } - - sCachedProject = findSupportProjectV7(); - return sCachedProject; - } - - @Nullable - private static IProject findSupportProjectV7() { - for (IJavaProject javaProject : AdtUtils.getOpenAndroidProjects()) { - IProject project = javaProject.getProject(); - ProjectState state = Sdk.getProjectState(project); - if (state != null && state.isLibrary()) { - ManifestInfo manifestInfo = ManifestInfo.get(project); - if (manifestInfo.getPackage().equals("android.support.v7.gridlayout")) { //$NON-NLS-1$ - return project; - } - } - } - - return null; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/XmlErrorHandler.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/XmlErrorHandler.java deleted file mode 100644 index c496c7e57..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/XmlErrorHandler.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * 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.project; - -import com.android.ide.common.xml.AndroidManifestParser.ManifestErrorHandler; -import com.android.ide.eclipse.adt.AdtConstants; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IMarker; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.jdt.core.IJavaProject; -import org.xml.sax.Locator; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; -import org.xml.sax.helpers.DefaultHandler; - -/** - * XML error handler used by the parser to report errors/warnings. - */ -public class XmlErrorHandler extends DefaultHandler implements ManifestErrorHandler { - - private final IJavaProject mJavaProject; - /** file being parsed */ - private final IFile mFile; - /** link to the delta visitor, to set the xml error flag */ - private final XmlErrorListener mErrorListener; - - /** - * Classes which implement this interface provide a method that deals - * with XML errors. - */ - public interface XmlErrorListener { - /** - * Sent when an XML error is detected. - */ - public void errorFound(); - } - - public static class BasicXmlErrorListener implements XmlErrorListener { - public boolean mHasXmlError = false; - - @Override - public void errorFound() { - mHasXmlError = true; - } - } - - public XmlErrorHandler(IJavaProject javaProject, IFile file, XmlErrorListener errorListener) { - mJavaProject = javaProject; - mFile = file; - mErrorListener = errorListener; - } - - public XmlErrorHandler(IFile file, XmlErrorListener errorListener) { - this(null, file, errorListener); - } - - /** - * Xml Error call back - * @param exception the parsing exception - * @throws SAXException - */ - @Override - public void error(SAXParseException exception) throws SAXException { - handleError(exception, exception.getLineNumber()); - } - - /** - * Xml Fatal Error call back - * @param exception the parsing exception - * @throws SAXException - */ - @Override - public void fatalError(SAXParseException exception) throws SAXException { - handleError(exception, exception.getLineNumber()); - } - - /** - * Xml Warning call back - * @param exception the parsing exception - * @throws SAXException - */ - @Override - public void warning(SAXParseException exception) throws SAXException { - if (mFile != null) { - BaseProjectHelper.markResource(mFile, - AdtConstants.MARKER_XML, - exception.getMessage(), - exception.getLineNumber(), - IMarker.SEVERITY_WARNING); - } - } - - protected final IFile getFile() { - return mFile; - } - - /** - * Handles a parsing error and an optional line number. - * @param exception - * @param lineNumber - */ - @Override - public void handleError(Exception exception, int lineNumber) { - if (mErrorListener != null) { - mErrorListener.errorFound(); - } - - String message = exception.getMessage(); - if (message == null) { - message = "Unknown error " + exception.getClass().getCanonicalName(); - } - - if (mFile != null) { - BaseProjectHelper.markResource(mFile, - AdtConstants.MARKER_XML, - message, - lineNumber, - IMarker.SEVERITY_ERROR); - } - } - - /** - * Checks that a class is valid and can be used in the Android Manifest. - * <p/> - * Errors are put as {@link IMarker} on the manifest file. - * @param locator - * @param className the fully qualified name of the class to test. - * @param superClassName the fully qualified name of the class it is supposed to extend. - * @param testVisibility if <code>true</code>, the method will check the visibility of - * the class or of its constructors. - */ - @Override - public void checkClass(Locator locator, String className, String superClassName, - boolean testVisibility) { - if (mJavaProject == null) { - return; - } - // we need to check the validity of the activity. - String result = BaseProjectHelper.testClassForManifest(mJavaProject, - className, superClassName, testVisibility); - if (result != BaseProjectHelper.TEST_CLASS_OK) { - // get the line number - int line = locator.getLineNumber(); - - // mark the file - IMarker marker = BaseProjectHelper.markResource(getFile(), - AdtConstants.MARKER_ANDROID, result, line, IMarker.SEVERITY_ERROR); - - // add custom attributes to be used by the manifest editor. - if (marker != null) { - try { - marker.setAttribute(AdtConstants.MARKER_ATTR_TYPE, - AdtConstants.MARKER_ATTR_TYPE_ACTIVITY); - marker.setAttribute(AdtConstants.MARKER_ATTR_CLASS, className); - } catch (CoreException e) { - } - } - } - } -} |