Automated import from //branches/master/...@140469,140469
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigDelegate.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigDelegate.java
index 05cc6ae..a624b00 100755
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigDelegate.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigDelegate.java
@@ -18,10 +18,11 @@
 
 import com.android.ide.eclipse.adt.AdtPlugin;
 import com.android.ide.eclipse.adt.launch.AndroidLaunch;
+import com.android.ide.eclipse.adt.launch.AndroidLaunchConfiguration;
 import com.android.ide.eclipse.adt.launch.AndroidLaunchController;
 import com.android.ide.eclipse.adt.launch.IAndroidLaunchAction;
 import com.android.ide.eclipse.adt.launch.LaunchConfigDelegate;
-import com.android.ide.eclipse.adt.launch.AndroidLaunchConfiguration;
+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.runtime.IProgressMonitor;
 import org.eclipse.debug.core.ILaunchConfiguration;
 import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.internal.junit.launcher.JUnitLaunchConfigurationConstants;
 import org.eclipse.jdt.internal.junit.launcher.TestKindRegistry;
 
@@ -46,6 +48,7 @@
 
     /** Launch config attribute that stores instrumentation runner */
     static final String ATTR_INSTR_NAME = AdtPlugin.PLUGIN_ID + ".instrumentation"; //$NON-NLS-1$
+    static final String INSTRUMENTATION_OK = null;
     private static final String EMPTY_STRING = ""; //$NON-NLS-1$
 
     @Override
@@ -87,7 +90,8 @@
      * Helper method to return the set of instrumentations for the Android project
      * 
      * @param project the {@link IProject} to get instrumentations for
-     * @return null if no error occurred parsing instrumentations
+     * @return null if error occurred parsing instrumentations, otherwise returns array of
+     * instrumentation class names
      */
     static String[] getInstrumentationsForProject(IProject project) {
         if (project != null) {
@@ -117,4 +121,56 @@
         config.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_RUNNER_KIND, 
                 TestKindRegistry.JUNIT3_TEST_KIND_ID);
     }
+    
+    /**
+     * Helper method to determine if specified instrumentation can be used as a test runner
+     * 
+     * @param project the {@link IJavaProject} to validate
+     * @param instrumentation the instrumentation class name to validate
+     * @return <code>INSTRUMENTATION_OK</code> if valid, otherwise returns error message
+     */
+    static String validateInstrumentationRunner(IJavaProject project, String instrumentation) {
+        AndroidManifestParser manifestParser;
+        try {
+            manifestParser = AndroidManifestParser.parse(
+                    project, null /* errorListener */,
+                    true /* gatherData */, false /* markErrors */);
+            // check if this instrumentation is the standard test runner
+            if (!instrumentation.equals(AndroidConstants.CLASS_INSTRUMENTATION_RUNNER)) {
+                // check if it extends the standard test runner
+                String result = BaseProjectHelper.testClassForManifest(project,
+                        instrumentation, AndroidConstants.CLASS_INSTRUMENTATION_RUNNER, true);
+                if (result != BaseProjectHelper.TEST_CLASS_OK) {
+                    return String.format("The instrumentation runner must be of type %s", 
+                            AndroidConstants.CLASS_INSTRUMENTATION_RUNNER);
+                }
+            }
+            if (!hasTestRunnerLibrary(manifestParser)) {
+                return String.format("%s does not not use the %s library", 
+                        project.getProject().getName(), AndroidConstants.LIBRARY_TEST_RUNNER);
+            }
+        } catch (CoreException e) {
+            String err = String.format("Error parsing AndroidManifest for %s", 
+                    project.getProject().getName());
+            AdtPlugin.log(e, err);
+            return err;
+        }  
+        return INSTRUMENTATION_OK;
+    }
+ 
+    /**
+     * Helper method to determine if given manifest has a <code>AndroidConstants.LIBRARY_TEST_RUNNER
+     * </code> library reference
+     *
+     * @param manifestParser the {@link AndroidManifestParser} to search
+     * @return true if test runner library found, false otherwise
+     */
+    static boolean hasTestRunnerLibrary(AndroidManifestParser manifestParser) {
+       for (String lib : manifestParser.getUsesLibraries()) {
+           if (lib.equals(AndroidConstants.LIBRARY_TEST_RUNNER)) {
+               return true;
+           }
+       }
+       return false;
+    }
 }
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigurationTab.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigurationTab.java
index 5fbda98..aa59a51 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigurationTab.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigurationTab.java
@@ -691,10 +691,18 @@
     private void validateInstrumentation(IJavaProject javaProject) {
         if (mInstrumentations == null || mInstrumentations.length < 1) {
             setErrorMessage("Specified project has no defined instrumentations");
+            return;
         }
         String instrumentation = getSelectedInstrumentation();
         if (instrumentation == null) {
             setErrorMessage("Instrumentation not specified");
+            return;
+        }
+        String result = AndroidJUnitLaunchConfigDelegate.validateInstrumentationRunner(
+                javaProject, instrumentation);
+        if (result != AndroidJUnitLaunchConfigDelegate.INSTRUMENTATION_OK) {
+            setErrorMessage(result);
+            return;
         }
     }
 
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchShortcut.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchShortcut.java
index e03f282..30649e2 100755
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchShortcut.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchShortcut.java
@@ -16,6 +16,9 @@
 
 package com.android.ide.eclipse.adt.launch.junit;
 
+import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.common.AndroidConstants;
+
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
@@ -34,7 +37,7 @@
 
     /**
      * Creates a default Android JUnit launch configuration. Sets the instrumentation runner to the
-     * first instrumentation found in the AndroidManifest.  
+     * first instrumentation found in the AndroidManifest.
      */
     @Override
     protected ILaunchConfigurationWorkingCopy createLaunchConfiguration(IJavaElement element)
@@ -43,10 +46,27 @@
         IProject project = element.getResource().getProject();
         String[] instrumentations = 
             AndroidJUnitLaunchConfigDelegate.getInstrumentationsForProject(project);
-        if (instrumentations != null && instrumentations.length > 0) {
-            // just pick the first runner
-            config.setAttribute(AndroidJUnitLaunchConfigDelegate.ATTR_INSTR_NAME, 
-                    instrumentations[0]);
+        boolean runnerFound = false;
+        if (instrumentations != null) {
+            // just pick the first valid runner
+            for (String instr : instrumentations) {
+                if (AndroidJUnitLaunchConfigDelegate.validateInstrumentationRunner(
+                        element.getJavaProject(),  instr) == 
+                            AndroidJUnitLaunchConfigDelegate.INSTRUMENTATION_OK) {
+
+                    config.setAttribute(AndroidJUnitLaunchConfigDelegate.ATTR_INSTR_NAME, 
+                        instr);
+                    runnerFound = true;
+                    break;
+                }
+            }
+        }
+        if (!runnerFound) {
+            // TODO: put this in a string properties
+            String msg = String.format("ERROR: Application does not specify a %s instrumentation or does not declare uses-library %s",
+                    AndroidConstants.CLASS_INSTRUMENTATION_RUNNER, 
+                    AndroidConstants.LIBRARY_TEST_RUNNER);
+            AdtPlugin.printErrorToConsole(project, msg);           
         }
         AndroidJUnitLaunchConfigDelegate.setJUnitDefaults(config);
 
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java
index 5abfd81..1da753c 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java
@@ -180,6 +180,8 @@
     public final static String CLASS_BROADCASTRECEIVER = "android.content.BroadcastReceiver"; //$NON-NLS-1$ 
     public final static String CLASS_CONTENTPROVIDER = "android.content.ContentProvider"; //$NON-NLS-1$
     public final static String CLASS_INSTRUMENTATION = "android.app.Instrumentation"; //$NON-NLS-1$
+    public final static String CLASS_INSTRUMENTATION_RUNNER =
+        "android.test.InstrumentationTestRunner"; //$NON-NLS-1$
     public final static String CLASS_BUNDLE = "android.os.Bundle"; //$NON-NLS-1$
     public final static String CLASS_R = "android.R"; //$NON-NLS-1$
     public final static String CLASS_MANIFEST_PERMISSION = "android.Manifest$permission"; //$NON-NLS-1$
@@ -215,4 +217,5 @@
     /** The base URL where to find the Android class & manifest documentation */
     public static final String CODESITE_BASE_URL = "http://code.google.com/android";  //$NON-NLS-1$
     
+    public static final String LIBRARY_TEST_RUNNER = "android.test.runner"; // $NON-NLS-1$
 }
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java
index 42c881b..fe11e69 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java
@@ -255,12 +255,8 @@
                                 } catch (NumberFormatException e) {
                                     handleError(e, -1 /* lineNumber */);
                                 }
-                            }  else if (NODE_INSTRUMENTATION.equals(localName)) {
-                                value = getAttributeValue(attributes, ATTRIBUTE_NAME,
-                                        true /* hasNamespace */);
-                                if (value != null) {
-                                    mInstrumentations.add(value);
-                                }
+                            } else if (NODE_INSTRUMENTATION.equals(localName)) {
+                                processInstrumentationNode(attributes);
                             }    
                             break;
                         case LEVEL_ACTIVITY:
@@ -449,6 +445,25 @@
                 addProcessName(processName);
             }
         }
+        
+        /**
+         * Processes the instrumentation nodes.
+         * @param attributes the attributes for the activity node.
+         * node is representing
+         */
+        private void processInstrumentationNode(Attributes attributes) {
+            // lets get the class name, and check it if required.
+            String instrumentationName = getAttributeValue(attributes, ATTRIBUTE_NAME,
+                    true /* hasNamespace */);
+            if (instrumentationName != null) {
+                String instrClassName = combinePackageAndClassName(mPackage, instrumentationName);
+                mInstrumentations.add(instrClassName);
+                if (mMarkErrors) {
+                    checkClass(instrClassName, AndroidConstants.CLASS_INSTRUMENTATION,
+                            true /* testVisibility */);
+                }
+            }
+        }
 
         /**
          * Checks that a class is valid and can be used in the Android Manifest.
@@ -484,8 +499,7 @@
                     } catch (CoreException e) {
                     }
                 }
-            }
-            
+            }           
         }
 
         /**
@@ -583,7 +597,7 @@
 
         return null;
     }
-    
+
     /**
      * Parses the Android Manifest, and returns an object containing the result of the parsing.
      * <p/>