From 74cadd7ccc3b617d9520e56af7f2a121293bd1fe Mon Sep 17 00:00:00 2001 From: snpe Date: Fri, 20 Aug 2010 00:01:42 +0200 Subject: Enhance Android Classpath Container Change-Id: Iaa4f1ea8766dbeb9054ca3dc1445f5154f841c44 --- .../plugins/com.android.ide.eclipse.adt/plugin.xml | 19 +- .../AndroidClasspathContainerInitializer.java | 257 +++++++++++++++++++-- .../project/AndroidClasspathContainerPage.java | 193 ++++++++++++++++ .../sourcelookup/AdtSourceLookupDirector.java | 97 ++++++++ 4 files changed, 541 insertions(+), 25 deletions(-) create mode 100644 eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidClasspathContainerPage.java create mode 100755 eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sourcelookup/AdtSourceLookupDirector.java (limited to 'eclipse/plugins') diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml index e6a5e82..4dfeadc 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml +++ b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml @@ -411,6 +411,15 @@ + + + + + + + + + + list = new ArrayList(); // First, we create the IClasspathEntry for the framework. // now add the android framework to the class path. // create the path object. - IPath android_lib = new Path(paths[CACHE_INDEX_JAR]); - IPath android_src = new Path(paths[CACHE_INDEX_SRC]); + 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; + } + } - // create the java doc link. - IClasspathAttribute cpAttribute = JavaCore.newClasspathAttribute( - IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME, - paths[CACHE_INDEX_DOCS_URI]); + 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 access rule to restrict access to classes in com.android.internal - IAccessRule accessRule = JavaCore.newAccessRule( - new Path("com/android/internal/**"), //$NON-NLS-1$ + // create the java doc link. + String androidApiURL = ProjectHelper.loadStringProperty(root, PROPERTY_ANDROID_API); + String apiURL = null; + if (androidApiURL != null) { + apiURL = androidApiURL; + } else { + if (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) { + + 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(android_lib, - android_src, // source attachment path - null, // default source attachment root path. + IClasspathEntry frameworkClasspathEntry = JavaCore.newLibraryEntry(androidLib, + androidSrc, // source attachment path + null, // default source attachment root path. new IAccessRule[] { accessRule }, - new IClasspathAttribute[] { cpAttribute }, + attributes, false // not exported. ); @@ -469,12 +555,11 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit while (i < paths.length) { Path jarPath = new Path(paths[i++]); - IClasspathAttribute[] attributes = null; + attributes = null; if (docPath.length() > 0) { attributes = new IClasspathAttribute[] { - JavaCore.newClasspathAttribute( - IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME, - docPath) + JavaCore.newClasspathAttribute( + IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME, docPath) }; } @@ -490,9 +575,51 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit } } + 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; + } + + private static boolean testURL(String androidApiURL) { + boolean valid = false; + InputStream is = null; + try { + URL testURL = new URL(androidApiURL); + is = testURL.openStream(); + valid = true; + } catch (Exception ignore) { + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException ignore) { + } + } + } + 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. @@ -651,4 +778,86 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit 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(); + for (int j = 0; j < extraAttributtes.length; j++) { + IClasspathAttribute extraAttribute = extraAttributtes[j]; + if (IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME + .equals(extraAttribute.getName())) { + ProjectHelper.saveStringProperty(root, + PROPERTY_ANDROID_API, extraAttribute.getValue()); + + } + } + } + } + } + } + rebindClasspathEntries(project.getJavaModel(), containerPath); + } + } + } + + private static void rebindClasspathEntries(IJavaModel model, IPath containerPath) + throws JavaModelException { + ArrayList affectedProjects = new ArrayList(); + + 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 = (IJavaProject[]) 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 new file mode 100644 index 0000000..4641c22 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidClasspathContainerPage.java @@ -0,0 +1,193 @@ +/* + * 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.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"); + } + + public IClasspathEntry getSelection() { + IPath path = new Path(AndroidClasspathContainerInitializer.CONTAINER_ID); + + 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); + } + + 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); + } + } + + 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); + } + + 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)); + } + + 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/sourcelookup/AdtSourceLookupDirector.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sourcelookup/AdtSourceLookupDirector.java new file mode 100755 index 0000000..612ef76 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sourcelookup/AdtSourceLookupDirector.java @@ -0,0 +1,97 @@ +/* + * 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.sourcelookup; + +import com.android.ide.eclipse.adt.internal.project.AndroidClasspathContainerInitializer; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.sourcelookup.ISourceContainer; +import org.eclipse.debug.core.sourcelookup.containers.DefaultSourceContainer; +import org.eclipse.debug.core.sourcelookup.containers.DirectorySourceContainer; +import org.eclipse.debug.core.sourcelookup.containers.ExternalArchiveSourceContainer; +import org.eclipse.jdt.core.IClasspathEntry; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.internal.launching.JavaSourceLookupDirector; + +import java.io.File; + +public class AdtSourceLookupDirector extends JavaSourceLookupDirector { + + @Override + public void initializeDefaults(ILaunchConfiguration configuration) throws CoreException { + dispose(); + setLaunchConfiguration(configuration); + String projectName = configuration.getAttribute("org.eclipse.jdt.launching.PROJECT_ATTR", //$NON-NLS-1$ + ""); //$NON-NLS-1$ + if (projectName != null && projectName.length() > 0) { + IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName); + if (project != null && project.isOpen()) { + IJavaProject javaProject = JavaCore.create(project); + if (javaProject != null && javaProject.isOpen()) { + IClasspathEntry[] entries = javaProject.getRawClasspath(); + IClasspathEntry androidEntry = null; + for (int i = 0; i < entries.length; i++) { + IClasspathEntry entry = entries[i]; + if (entry.getPath() != null + && AndroidClasspathContainerInitializer.CONTAINER_ID.equals(entry + .getPath().toString())) { + androidEntry = entry; + break; + } + } + if (androidEntry != null) { + IPath sourceAttachmentPath = androidEntry.getSourceAttachmentPath(); + if (sourceAttachmentPath != null) { + String androidSrc = sourceAttachmentPath.toString(); + if (androidSrc != null && androidSrc.trim().length() > 0) { + File srcFile = new File(androidSrc); + ISourceContainer adtContainer = null; + if (srcFile.isFile()) { + adtContainer = new ExternalArchiveSourceContainer(androidSrc, + true); + } + if (srcFile.isDirectory()) { + adtContainer = new DirectorySourceContainer(srcFile, false); + } + if (adtContainer != null) { + ISourceContainer defaultContainer = + new DefaultSourceContainer(); + setSourceContainers(new ISourceContainer[] { + adtContainer, defaultContainer + }); + initializeParticipants(); + return; + } + } + } + } + } + } + } + setSourceContainers(new ISourceContainer[] { + new DefaultSourceContainer() + }); + initializeParticipants(); + } + +} -- cgit v1.1