AI 146570: am: CL 146336 am: CL 146335 ADT: Rework the Manifest class browser.
  For ADT #1603194, it is desirable to select the Instrumentation
  Runner class from the android.jar. The class browser was filtering
  it out. The class browser has been changed like this:
  - include all source & jar package roots
  - a checkbox let the user toggle between searching only sources
  (of the project) or anything in the classpath (thus include jars.)
  The default is to include everything for the instrumentation and only
  the source for other browsers.
  Also improved a bit the filter by not iterating over the hierarchy
  and filtering out abstract classes (which was not needed before.)
  Original author: raphael
  Merged from: //branches/cupcake/...
  Original author: android-build

Automated import of CL 146570
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/AndroidManifestDescriptors.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/AndroidManifestDescriptors.java
index 77c08b5..5d1abab 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/AndroidManifestDescriptors.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/AndroidManifestDescriptors.java
@@ -205,6 +205,7 @@
         overrideClassName(overrides, "receiver", AndroidConstants.CLASS_BROADCASTRECEIVER);  //$NON-NLS-1$
         overrideClassName(overrides, "service", AndroidConstants.CLASS_SERVICE);             //$NON-NLS-1$
         overrideClassName(overrides, "provider", AndroidConstants.CLASS_CONTENTPROVIDER);    //$NON-NLS-1$
+        overrideClassName(overrides, "instrumentation", AndroidConstants.CLASS_INSTRUMENTATION);    //$NON-NLS-1$
 
         // -- list element nodes already created --
         // These elements are referenced by already opened editors, so we want to update them
@@ -244,27 +245,42 @@
                 new DescriptorsUtils.ITextAttributeCreator() {
             public TextAttributeDescriptor create(String xmlName, String uiName, String nsUri,
                     String tooltip) {
+                uiName += "*";  //$NON-NLS-1$
                 if (AndroidConstants.CLASS_ACTIVITY.equals(className)) {
                     return new ClassAttributeDescriptor(
                             className,
                             PostActivityCreationAction.getAction(),
-                            xmlName, uiName + "*", //$NON-NLS-1$
+                            xmlName,
+                            uiName,
                             nsUri,
                             tooltip,
-                            true /*mandatory */);
+                            true /*mandatory */,
+                            true /*defaultToProjectOnly*/);
                 } else if (AndroidConstants.CLASS_BROADCASTRECEIVER.equals(className)) {
                     return new ClassAttributeDescriptor(
                             className,
                             PostReceiverCreationAction.getAction(),
-                            xmlName, uiName + "*", //$NON-NLS-1$
+                            xmlName,
+                            uiName,
                             nsUri,
                             tooltip,
-                            true /*mandatory */);
-                    
+                            true /*mandatory */,
+                            true /*defaultToProjectOnly*/);
+                } else if (AndroidConstants.CLASS_INSTRUMENTATION.equals(className)) {
+                    return new ClassAttributeDescriptor(
+                            className,
+                            null, // no post action
+                            xmlName,
+                            uiName,
+                            nsUri,
+                            tooltip,
+                            true /*mandatory */,
+                            false /*defaultToProjectOnly*/);
                 } else {
                     return new ClassAttributeDescriptor(
                             className,
-                            xmlName, uiName + "*", //$NON-NLS-1$
+                            xmlName,
+                            uiName,
                             nsUri,
                             tooltip,
                             true /*mandatory */);
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ApplicationAttributeDescriptor.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ApplicationAttributeDescriptor.java
index eab7f09..98d0fe8 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ApplicationAttributeDescriptor.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ApplicationAttributeDescriptor.java
@@ -39,6 +39,7 @@
     @Override
     public UiAttributeNode createUiNode(UiElementNode uiParent) {
         return new UiClassAttributeNode("android.app.Application", //$NON-NLS-1$
-                null /* postCreationAction */, false /* mandatory */, this, uiParent);
+                null /* postCreationAction */, false /* mandatory */, this, uiParent,
+                true /*defaultToProjectOnly*/);
     }
 }
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ClassAttributeDescriptor.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ClassAttributeDescriptor.java
index 629b37c..d1a76e0 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ClassAttributeDescriptor.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ClassAttributeDescriptor.java
@@ -36,6 +36,8 @@
     
     /** indicates if the class parameter is mandatory */
     boolean mMandatory;
+
+    private final boolean mDefaultToProjectOnly;
     
     /**
      * Creates a new {@link ClassAttributeDescriptor}
@@ -49,10 +51,14 @@
      * @param mandatory indicates if the class attribute is mandatory.
      */
     public ClassAttributeDescriptor(String superClassName,
-            String xmlLocalName, String uiName, String nsUri,
-            String tooltip, boolean mandatory) {
+            String xmlLocalName,
+            String uiName,
+            String nsUri,
+            String tooltip,
+            boolean mandatory) {
         super(xmlLocalName, uiName, nsUri, tooltip);
         mSuperClassName = superClassName;
+        mDefaultToProjectOnly = true;
     }
 
     /**
@@ -67,14 +73,21 @@
      *              See {@link SdkConstants#NS_RESOURCES} for a common value.
      * @param tooltip A non-empty tooltip string or null.
      * @param mandatory indicates if the class attribute is mandatory.
+     * @param defaultToProjectOnly True if only classes from the sources of this project should
+     *         be shown by default in the class browser.
      */
     public ClassAttributeDescriptor(String superClassName,
             IPostTypeCreationAction postCreationAction,
-            String xmlLocalName, String uiName, String nsUri,
-            String tooltip, boolean mandatory) {
+            String xmlLocalName,
+            String uiName,
+            String nsUri,
+            String tooltip,
+            boolean mandatory,
+            boolean defaultToProjectOnly) {
         super(xmlLocalName, uiName, nsUri, tooltip);
         mSuperClassName = superClassName;
         mPostCreationAction = postCreationAction;
+        mDefaultToProjectOnly = defaultToProjectOnly;
     }
 
     /**
@@ -83,6 +96,6 @@
     @Override
     public UiAttributeNode createUiNode(UiElementNode uiParent) {
         return new UiClassAttributeNode(mSuperClassName, mPostCreationAction,
-                mMandatory, this, uiParent);
+                mMandatory, this, uiParent, mDefaultToProjectOnly);
     }
 }
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/InstrumentationAttributeDescriptor.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/InstrumentationAttributeDescriptor.java
deleted file mode 100644
index 6e589f7..0000000
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/InstrumentationAttributeDescriptor.java
+++ /dev/null
@@ -1,46 +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.editors.manifest.descriptors;
-
-import com.android.ide.eclipse.common.AndroidConstants;
-import com.android.ide.eclipse.editors.descriptors.TextAttributeDescriptor;
-import com.android.ide.eclipse.editors.manifest.model.UiClassAttributeNode;
-import com.android.ide.eclipse.editors.uimodel.UiAttributeNode;
-import com.android.ide.eclipse.editors.uimodel.UiElementNode;
-
-/**
- * Describes a 'Instrumentation' class XML attribute. It is displayed by a
- * {@link UiClassAttributeNode}, that restricts creation and selection to classes inheriting from
- * android.app.Instrumentation.
- */
-public class InstrumentationAttributeDescriptor extends TextAttributeDescriptor {
-
-    public InstrumentationAttributeDescriptor(String xmlLocalName, String uiName, String nsUri,
-            String tooltip) {
-        super(xmlLocalName, uiName, nsUri, tooltip);
-    }
-    
-    /**
-     * @return A new {@link UiClassAttributeNode} linked to this descriptor.
-     */
-    @Override
-    public UiAttributeNode createUiNode(UiElementNode uiParent) {
-        return new UiClassAttributeNode(AndroidConstants.CLASS_INSTRUMENTATION,
-                null /* postCreationAction */, true /* mandatory */, this, uiParent);
-    }
-}
-
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/model/UiClassAttributeNode.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/model/UiClassAttributeNode.java
index e32be86..c872b6f 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/model/UiClassAttributeNode.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/model/UiClassAttributeNode.java
@@ -16,6 +16,7 @@
 
 package com.android.ide.eclipse.editors.manifest.model;
 
+import com.android.ide.eclipse.adt.AdtPlugin;
 import com.android.ide.eclipse.common.AndroidConstants;
 import com.android.ide.eclipse.common.project.AndroidManifestParser;
 import com.android.ide.eclipse.common.project.BaseProjectHelper;
@@ -31,6 +32,7 @@
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.jdt.core.Flags;
 import org.eclipse.jdt.core.IClasspathEntry;
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IJavaProject;
@@ -63,6 +65,7 @@
 import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.Text;
 import org.eclipse.ui.IEditorInput;
 import org.eclipse.ui.IFileEditorInput;
@@ -90,20 +93,28 @@
     private String mReferenceClass;
     private IPostTypeCreationAction mPostCreationAction;
     private boolean mMandatory;
+    private final boolean mDefaultToProjectOnly;
     
     private class HierarchyTypeSelection extends TypeSelectionExtension {
         
         private IJavaProject mJavaProject;
+        private IType mReferenceType;
+        private Button mProjectOnly;
+        private boolean mUseProjectOnly;
 
-        public HierarchyTypeSelection(IProject project, String referenceClass) {
+        public HierarchyTypeSelection(IProject project, String referenceClass)
+                throws JavaModelException {
             mJavaProject = JavaCore.create(project);
-            mReferenceClass = referenceClass;
+            mReferenceType = mJavaProject.findType(referenceClass);
         }
 
         @Override
         public ITypeInfoFilterExtension getFilterExtension() {
             return new ITypeInfoFilterExtension() {
                 public boolean select(ITypeInfoRequestor typeInfoRequestor) {
+                    
+                    boolean projectOnly = mUseProjectOnly;
+                    
                     String packageName = typeInfoRequestor.getPackageName();
                     String typeName = typeInfoRequestor.getTypeName();
                     String enclosingType = typeInfoRequestor.getEnclosingName();
@@ -121,19 +132,35 @@
                     
                     try {
                         IType type = mJavaProject.findType(className);
-                        if (type != null) {
-                            // 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 return false;
-                            IType superType = type;
-                            while ((superType = hierarchy.getSuperclass(superType)) != null) {
-                                if (mReferenceClass.equals(superType.getFullyQualifiedName())) {
-                                    return true;
-                                }
+
+                        if (type == null) {
+                            return false;
+                        }
+
+                        // don't display abstract classes
+                        if ((type.getFlags() & Flags.AccAbstract) != 0) {
+                            return false;
+                        }
+
+                        // if project-only is selected, make sure the package fragment is
+                        // an actual source (thus "from this project").
+                        if (projectOnly) {
+                            IPackageFragment frag = type.getPackageFragment();
+                            if (frag == null || frag.getKind() != IPackageFragmentRoot.K_SOURCE) {
+                                return false;
+                            }
+                        }
+                        
+                        // get the type hierarchy and reference type is one of the super classes.
+                        ITypeHierarchy hierarchy = type.newSupertypeHierarchy(
+                                new NullProgressMonitor());
+                        
+                        IType[] supertypes = hierarchy.getAllSupertypes(type);
+                        int n = supertypes.length;
+                        for (int i = 0; i < n; i++) {
+                            IType st = supertypes[i];
+                            if (mReferenceType.equals(st)) {
+                                return true;
                             }
                         }
                     } catch (JavaModelException e) {
@@ -143,6 +170,29 @@
                 }
             };
         }
+        
+        @Override
+        public Control createContentArea(Composite parent) {
+
+            mProjectOnly = new Button(parent, SWT.CHECK);
+            mProjectOnly.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+            mProjectOnly.setText(String.format("Display classes from sources of project '%s' only",
+                    mJavaProject.getProject().getName()));
+            
+            mUseProjectOnly = mDefaultToProjectOnly;
+            mProjectOnly.setSelection(mUseProjectOnly);
+            
+            mProjectOnly.addSelectionListener(new SelectionAdapter() {
+                @Override
+                public void widgetSelected(SelectionEvent e) {
+                    super.widgetSelected(e);
+                    mUseProjectOnly = mProjectOnly.getSelection();
+                    getTypeSelectionComponent().triggerSearch();
+                }
+            });
+            
+            return super.createContentArea(parent);
+        }
     }
 
     /**
@@ -165,14 +215,18 @@
      * modification of the class.
      * @param mandatory indicates if the class value is mandatory
      * @param attributeDescriptor the {@link AttributeDescriptor} object linked to the Ui Node.
+     * @param defaultToProjectOnly When true display classes of this project only by default.
+     *         When false any class path will be considered. The user can always toggle this. 
      */
     public UiClassAttributeNode(String referenceClass, IPostTypeCreationAction postCreationAction,
-            boolean mandatory, AttributeDescriptor attributeDescriptor, UiElementNode uiParent) {
+            boolean mandatory, AttributeDescriptor attributeDescriptor, UiElementNode uiParent,
+            boolean defaultToProjectOnly) {
         super(attributeDescriptor, uiParent);
         
         mReferenceClass = referenceClass;
         mPostCreationAction = postCreationAction;
         mMandatory = mandatory;
+        mDefaultToProjectOnly = defaultToProjectOnly;
     }
 
     /* (non-java doc)
@@ -292,8 +346,11 @@
             
             // Create a search scope including only the source folder of the current
             // project.
+            IPackageFragmentRoot[] packageFragmentRoots = getPackageFragmentRoots(project,
+                    true /*include_containers*/);
             IJavaSearchScope scope = SearchEngine.createJavaSearchScope(
-                    getPackageFragmentRoots(project), false);
+                    packageFragmentRoots,
+                    false);
 
             try {
                 SelectionDialog dlg = JavaUI.createTypeDialog(text.getShell(),
@@ -301,7 +358,7 @@
                     scope,
                     IJavaElementSearchConstants.CONSIDER_CLASSES,  // style
                     false, // no multiple selection
-                    "**", //$NON-NLS-1$ //filter
+                    "**",  //$NON-NLS-1$ //filter
                     new HierarchyTypeSelection(project, mReferenceClass));
                 dlg.setMessage(String.format("Select class name for element %1$s:",
                         getUiParent().getBreadcrumbTrailDescription(false /* include_root */)));
@@ -316,6 +373,7 @@
                     }
                 }
             } catch (JavaModelException e1) {
+                AdtPlugin.log(e1, "UiClassAttributeNode HandleBrowser failed");
             }
         }
     }
@@ -363,7 +421,9 @@
                     }
                 }
             } catch (JavaModelException e) {
+                AdtPlugin.log(e, "UiClassAttributeNode HandleLabel failed");
             } catch (PartInitException e) {
+                AdtPlugin.log(e, "UiClassAttributeNode HandleLabel failed");
             }
         }
     }
@@ -403,16 +463,20 @@
      * Computes and return the {@link IPackageFragmentRoot}s corresponding to the source folders of
      * the specified project.
      * @param project the project
+     * @param b 
      * @return an array of IPackageFragmentRoot.
      */
-    private IPackageFragmentRoot[] getPackageFragmentRoots(IProject project) {
+    private IPackageFragmentRoot[] getPackageFragmentRoots(IProject project,
+            boolean include_containers) {
         ArrayList<IPackageFragmentRoot> result = new ArrayList<IPackageFragmentRoot>();
         try {
             IJavaProject javaProject = JavaCore.create(project);
             IPackageFragmentRoot[] roots = javaProject.getPackageFragmentRoots();
             for (int i = 0; i < roots.length; i++) {
                 IClasspathEntry entry = roots[i].getRawClasspathEntry();
-                if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
+                if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE ||
+                        (include_containers &&
+                                entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER)) {
                     result.add(roots[i]);
                 }
             }
@@ -457,7 +521,8 @@
         page.setSuperClass(mReferenceClass, true /* canBeModified */);
         
         // get the source folders as java elements.
-        IPackageFragmentRoot[] roots = getPackageFragmentRoots(getProject());
+        IPackageFragmentRoot[] roots = getPackageFragmentRoots(getProject(),
+                true /*include_containers*/);
 
         IPackageFragmentRoot currentRoot = null;
         IPackageFragment currentFragment = null;