OSDN Git Service

Enhance Android Classpath Container
authorsnpe <snpe@snpe.rs>
Thu, 19 Aug 2010 22:01:42 +0000 (00:01 +0200)
committersnpe <snpe@snpe.rs>
Fri, 10 Sep 2010 20:33:44 +0000 (22:33 +0200)
Change-Id: Iaa4f1ea8766dbeb9054ca3dc1445f5154f841c44

eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidClasspathContainerInitializer.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidClasspathContainerPage.java [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sourcelookup/AdtSourceLookupDirector.java [new file with mode: 0755]

index e6a5e82..4dfeadc 100644 (file)
       </classpathContainerInitializer>
    </extension>
    <extension
+                point="org.eclipse.jdt.ui.classpathContainerPage">
+    <classpathContainerPage
+      name="Android Classpath Container"
+      class="com.android.ide.eclipse.adt.internal.project.AndroidClasspathContainerPage"
+      id="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK">
+    </classpathContainerPage>
+   </extension>
+
+   <extension
          point="org.eclipse.ui.exportWizards">
       <category
             id="com.android.ide.eclipse.wizards.category"
             modes="run,debug"
             name="Android JUnit Test"
             public="true"
-            sourceLocatorId="org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector"
+            sourceLocatorId="com.android.ide.eclipse.adt.internal.sourcelookup.AdtSourceLookupDirector"
             sourcePathComputerId="org.eclipse.jdt.launching.sourceLookup.javaSourcePathComputer">
       </launchConfigurationType>
    </extension>
+   <extension point="org.eclipse.debug.core.sourceLocators">
+     <sourceLocator
+       id="com.android.ide.eclipse.adt.internal.sourcelookup.AdtSourceLookupDirector"
+       class="com.android.ide.eclipse.adt.internal.sourcelookup.AdtSourceLookupDirector"
+       name="%sourceLocator.name">
+     </sourceLocator>
+   </extension>
+
    <extension
          point="org.eclipse.debug.ui.launchConfigurationTypeImages">
       <launchConfigurationTypeImage
index 402e24a..50df52a 100644 (file)
@@ -21,18 +21,24 @@ import com.android.ide.eclipse.adt.AndroidConstants;
 import com.android.ide.eclipse.adt.internal.sdk.LoadStatus;
 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.android.sdklib.SdkConstants;
 
 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.FileLocator;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.NullProgressMonitor;
 import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.core.runtime.jobs.Job;
 import org.eclipse.jdt.core.ClasspathContainerInitializer;
@@ -40,13 +46,18 @@ 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.util.ArrayList;
 import java.util.HashSet;
 import java.util.regex.Pattern;
@@ -56,8 +67,21 @@ import java.util.regex.Pattern;
  * {@link IProject}s. This removes the hard-coded path to the android.jar.
  */
 public class AndroidClasspathContainerInitializer extends ClasspathContainerInitializer {
+
+    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$
+
     /** The container id for the android framework jar file */
-    private final static String CONTAINER_ID =
+    public final static String CONTAINER_ID =
         "com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"; //$NON-NLS-1$
 
     /** path separator to store multiple paths in a single property. This is guaranteed to not
@@ -155,6 +179,7 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit
 
         String markerMessage = null;
         boolean outputToConsole = true;
+        IAndroidTarget target = null;
 
         try {
             AdtPlugin plugin = AdtPlugin.getDefault();
@@ -170,7 +195,7 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit
                             "Project has no default.properties file! Edit the project properties to set one.");
                 } else {
                     // this might be null if the sdk is not yet loaded.
-                    IAndroidTarget target = state.getTarget();
+                    target = state.getTarget();
 
                     // if we are loaded and the target is non null, we create a valid
                     // ClassPathContainer
@@ -207,7 +232,7 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit
                         // 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);
+                        AndroidClasspathContainer container = getContainerFromCache(iProject, target);
 
                         if (container == null) {
                             // either the cache was wrong (ie folder does not exists anymore), or
@@ -343,7 +368,7 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit
         String[] paths = getTargetPaths(target);
 
         // create the classpath entry from the paths
-        IClasspathEntry[] entries = createClasspathEntriesFromPaths(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
@@ -364,7 +389,8 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit
     /**
      * Generates an {@link AndroidClasspathContainer} from the project cache, if possible.
      */
-    private static AndroidClasspathContainer getContainerFromCache(IProject project) {
+    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);
@@ -423,7 +449,7 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit
             return null;
         }
 
-        IClasspathEntry[] entries = createClasspathEntriesFromPaths(paths);
+        IClasspathEntry[] entries = createClasspathEntriesFromPaths(paths, target);
 
         return new AndroidClasspathContainer(entries,
                 new Path(CONTAINER_ID), targetNameCache);
@@ -433,30 +459,90 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit
      * Generates an array of {@link IClasspathEntry} from a set of paths.
      * @see #getTargetPaths(IAndroidTarget)
      */
-    private static IClasspathEntry[] createClasspathEntriesFromPaths(String[] paths) {
+    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 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 (file)
index 0000000..4641c22
--- /dev/null
@@ -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 (executable)
index 0000000..612ef76
--- /dev/null
@@ -0,0 +1,97 @@
+/*\r
+ * Copyright (C) 2010 The Android Open Source Project\r
+ *\r
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.eclipse.org/org/documents/epl-v10.php\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ *\r
+ *******************************************************************************/\r
+\r
+package com.android.ide.eclipse.adt.internal.sourcelookup;\r
+\r
+import com.android.ide.eclipse.adt.internal.project.AndroidClasspathContainerInitializer;\r
+\r
+import org.eclipse.core.resources.IProject;\r
+import org.eclipse.core.resources.ResourcesPlugin;\r
+import org.eclipse.core.runtime.CoreException;\r
+import org.eclipse.core.runtime.IPath;\r
+import org.eclipse.debug.core.ILaunchConfiguration;\r
+import org.eclipse.debug.core.sourcelookup.ISourceContainer;\r
+import org.eclipse.debug.core.sourcelookup.containers.DefaultSourceContainer;\r
+import org.eclipse.debug.core.sourcelookup.containers.DirectorySourceContainer;\r
+import org.eclipse.debug.core.sourcelookup.containers.ExternalArchiveSourceContainer;\r
+import org.eclipse.jdt.core.IClasspathEntry;\r
+import org.eclipse.jdt.core.IJavaProject;\r
+import org.eclipse.jdt.core.JavaCore;\r
+import org.eclipse.jdt.internal.launching.JavaSourceLookupDirector;\r
+\r
+import java.io.File;\r
+\r
+public class AdtSourceLookupDirector extends JavaSourceLookupDirector {\r
+\r
+    @Override\r
+    public void initializeDefaults(ILaunchConfiguration configuration) throws CoreException {\r
+        dispose();\r
+        setLaunchConfiguration(configuration);\r
+        String projectName = configuration.getAttribute("org.eclipse.jdt.launching.PROJECT_ATTR", //$NON-NLS-1$\r
+                ""); //$NON-NLS-1$\r
+        if (projectName != null && projectName.length() > 0) {\r
+            IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);\r
+            if (project != null && project.isOpen()) {\r
+                IJavaProject javaProject = JavaCore.create(project);\r
+                if (javaProject != null && javaProject.isOpen()) {\r
+                    IClasspathEntry[] entries = javaProject.getRawClasspath();\r
+                    IClasspathEntry androidEntry = null;\r
+                    for (int i = 0; i < entries.length; i++) {\r
+                        IClasspathEntry entry = entries[i];\r
+                        if (entry.getPath() != null\r
+                                && AndroidClasspathContainerInitializer.CONTAINER_ID.equals(entry\r
+                                        .getPath().toString())) {\r
+                            androidEntry = entry;\r
+                            break;\r
+                        }\r
+                    }\r
+                    if (androidEntry != null) {\r
+                        IPath sourceAttachmentPath = androidEntry.getSourceAttachmentPath();\r
+                        if (sourceAttachmentPath != null) {\r
+                            String androidSrc = sourceAttachmentPath.toString();\r
+                            if (androidSrc != null && androidSrc.trim().length() > 0) {\r
+                                File srcFile = new File(androidSrc);\r
+                                ISourceContainer adtContainer = null;\r
+                                if (srcFile.isFile()) {\r
+                                    adtContainer = new ExternalArchiveSourceContainer(androidSrc,\r
+                                            true);\r
+                                }\r
+                                if (srcFile.isDirectory()) {\r
+                                    adtContainer = new DirectorySourceContainer(srcFile, false);\r
+                                }\r
+                                if (adtContainer != null) {\r
+                                    ISourceContainer defaultContainer =\r
+                                        new DefaultSourceContainer();\r
+                                    setSourceContainers(new ISourceContainer[] {\r
+                                            adtContainer, defaultContainer\r
+                                    });\r
+                                    initializeParticipants();\r
+                                    return;\r
+                                }\r
+                            }\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+        }\r
+        setSourceContainers(new ISourceContainer[] {\r
+            new DefaultSourceContainer()\r
+        });\r
+        initializeParticipants();\r
+    }\r
+\r
+}\r