auto import from //branches/cupcake_rel/...@138607
diff --git a/tools/eclipse/changes.txt b/tools/eclipse/changes.txt
index 781930c..8cd843e 100644
--- a/tools/eclipse/changes.txt
+++ b/tools/eclipse/changes.txt
@@ -1,4 +1,5 @@
 0.9.0 (work in progress)
+- Projects now store generated Java files (R.java/Manifest.java and output from aidl) in a 'gen' source folder.
 - Support for the new Android SDK with support for multiple versions of the Android platform and for vendor supplied add-ons.
     * New Project Wizard lets you choose which platform/add-on to target.
     * Project properties (right click project in Package Explorer, then "Properties"), lets you edit project target.
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml b/tools/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
index f86f5b2..39e6dd5 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
@@ -481,6 +481,12 @@
                style="push"
                toolbarPath="android_project"
                tooltip="Opens a wizard to help create a new Android XML file">
+               <enablement>
+                   <objectState
+                        name="projectNature"
+                        value="com.android.ide.eclipse.adt.AndroidNature">
+                   </objectState>
+               </enablement>
          </action>
          <action
                class="com.android.ide.eclipse.adt.wizards.actions.NewProjectAction"
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java
index 18d9745..f8a969e 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java
@@ -966,9 +966,10 @@
      * @param javaProject the javaProject object.
      * @param referencedJavaProjects the java projects that this project references.
      * @throws IOException 
+     * @throws CoreException 
      */
     private void writeStandardResources(SignedJarBuilder jarBuilder, IJavaProject javaProject,
-            IJavaProject[] referencedJavaProjects) throws IOException {
+            IJavaProject[] referencedJavaProjects) throws IOException, CoreException {
         IWorkspace ws = ResourcesPlugin.getWorkspace();
         IWorkspaceRoot wsRoot = ws.getRoot();
         
@@ -978,7 +979,9 @@
         writeStandardProjectResources(jarBuilder, javaProject, wsRoot, list);
         
         for (IJavaProject referencedJavaProject : referencedJavaProjects) {
-            writeStandardProjectResources(jarBuilder, referencedJavaProject, wsRoot, list);
+            if (referencedJavaProject.getProject().hasNature(AndroidConstants.NATURE)) {
+                writeStandardProjectResources(jarBuilder, referencedJavaProject, wsRoot, list);
+            }
         }
     }
     
@@ -1067,7 +1070,9 @@
     }
 
     /**
-     * Returns the list of the output folders for the specified {@link IJavaProject} objects.
+     * Returns the list of the output folders for the specified {@link IJavaProject} objects, if
+     * they are Android projects.
+     * 
      * @param referencedJavaProjects the java projects.
      * @return an array, always. Can be empty.
      * @throws CoreException
@@ -1079,19 +1084,21 @@
         IWorkspaceRoot wsRoot = ws.getRoot();
 
         for (IJavaProject javaProject : referencedJavaProjects) {
-            // get the output folder
-            IPath path = null;
-            try {
-                path = javaProject.getOutputLocation();
-            } catch (JavaModelException e) {
-                continue;
-            }
-
-            IResource outputResource = wsRoot.findMember(path);
-            if (outputResource != null && outputResource.getType() == IResource.FOLDER) {
-                String outputOsPath = outputResource.getLocation().toOSString();
-
-                list.add(outputOsPath);
+            if (javaProject.getProject().hasNature(AndroidConstants.NATURE)) {
+                // get the output folder
+                IPath path = null;
+                try {
+                    path = javaProject.getOutputLocation();
+                } catch (JavaModelException e) {
+                    continue;
+                }
+    
+                IResource outputResource = wsRoot.findMember(path);
+                if (outputResource != null && outputResource.getType() == IResource.FOLDER) {
+                    String outputOsPath = outputResource.getLocation().toOSString();
+    
+                    list.add(outputOsPath);
+                }
             }
         }
 
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AMReceiver.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AMReceiver.java
new file mode 100644
index 0000000..8fdcdf9
--- /dev/null
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AMReceiver.java
@@ -0,0 +1,160 @@
+/*
+ * 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.launch;
+
+import com.android.ddmlib.IDevice;
+import com.android.ddmlib.MultiLineReceiver;
+import com.android.ide.eclipse.adt.AdtPlugin;
+
+import java.util.ArrayList;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+/**
+ * Output receiver for am process (Activity Manager)
+ * 
+ * Monitors adb output for am errors, and retries launch as appropriate. 
+ */
+public class AMReceiver extends MultiLineReceiver {
+
+    private static final int MAX_ATTEMPT_COUNT = 5;
+    private static final Pattern sAmErrorType = Pattern.compile("Error type (\\d+)"); //$NON-NLS-1$
+
+    private final DelayedLaunchInfo mLaunchInfo;
+    private final IDevice mDevice;
+    private final ILaunchController mLaunchController;
+
+    /**
+     * Basic constructor.
+     * 
+     * @param launchInfo the {@link DelayedLaunchInfo} associated with the am process.
+     * @param device the Android device on which the launch is done.
+     * @param launchController the {@link ILaunchController} that is managing the launch
+     */
+    public AMReceiver(DelayedLaunchInfo launchInfo, IDevice device, 
+            ILaunchController launchController) {
+        mLaunchInfo = launchInfo;
+        mDevice = device;
+        mLaunchController = launchController;
+    }
+
+    /**
+     * Monitors the am process for error messages. If an error occurs, will reattempt launch up to
+     * <code>MAX_ATTEMPT_COUNT</code> times.
+     * 
+     * @param lines a portion of the am output
+     * 
+     * @see MultiLineReceiver#processNewLines(String[])
+     */
+    @Override
+    public void processNewLines(String[] lines) {
+        // first we check if one starts with error
+        ArrayList<String> array = new ArrayList<String>();
+        boolean error = false;
+        boolean warning = false;
+        for (String s : lines) {
+            // ignore empty lines.
+            if (s.length() == 0) {
+                continue;
+            }
+
+            // check for errors that output an error type, if the attempt count is still
+            // valid. If not the whole text will be output in the console
+            if (mLaunchInfo.getAttemptCount() < MAX_ATTEMPT_COUNT &&
+                    mLaunchInfo.isCancelled() == false) {
+                Matcher m = sAmErrorType.matcher(s);
+                if (m.matches()) {
+                    // get the error type
+                    int type = Integer.parseInt(m.group(1));
+
+                    final int waitTime = 3;
+                    String msg;
+
+                    switch (type) {
+                        case 1:
+                            /* Intended fall through */
+                        case 2:
+                            msg = String.format(
+                                    "Device not ready. Waiting %1$d seconds before next attempt.",
+                                    waitTime);
+                            break;
+                        case 3:
+                            msg = String.format(
+                                    "New package not yet registered with the system. Waiting %1$d seconds before next attempt.",
+                                    waitTime);
+                            break;
+                        default:
+                            msg = String.format(
+                                    "Device not ready (%2$d). Waiting %1$d seconds before next attempt.",
+                                    waitTime, type);
+                        break;
+
+                    }
+
+                    AdtPlugin.printToConsole(mLaunchInfo.getProject(), msg);
+
+                    // launch another thread, that waits a bit and attempts another launch
+                    new Thread("Delayed Launch attempt") {
+                        @Override
+                        public void run() {
+                            try {
+                                sleep(waitTime * 1000);
+                            } catch (InterruptedException e) {
+                                // ignore
+                            }
+
+                            mLaunchController.launchApp(mLaunchInfo, mDevice);
+                        }
+                    }.start();
+
+                    // no need to parse the rest
+                    return;
+                }
+            }
+
+            // check for error if needed
+            if (error == false && s.startsWith("Error:")) { //$NON-NLS-1$
+                error = true;
+            }
+            if (warning == false && s.startsWith("Warning:")) { //$NON-NLS-1$
+                warning = true;
+            }
+
+            // add the line to the list
+            array.add("ActivityManager: " + s); //$NON-NLS-1$
+        }
+
+        // then we display them in the console
+        if (warning || error) {
+            AdtPlugin.printErrorToConsole(mLaunchInfo.getProject(), array.toArray());
+        } else {
+            AdtPlugin.printToConsole(mLaunchInfo.getProject(), array.toArray());
+        }
+
+        // if error then we cancel the launch, and remove the delayed info
+        if (error) {
+            mLaunchController.stopLaunch(mLaunchInfo);
+        }
+    }
+
+    /**
+     * Returns true if launch has been cancelled
+     */
+    public boolean isCancelled() {
+        return mLaunchInfo.isCancelled();
+    }
+}
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/ActivityLaunchAction.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/ActivityLaunchAction.java
new file mode 100644
index 0000000..1aa5a9a
--- /dev/null
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/ActivityLaunchAction.java
@@ -0,0 +1,97 @@
+/*
+ * 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.launch;
+
+import com.android.ddmlib.IDevice;
+import com.android.ide.eclipse.adt.AdtPlugin;
+
+import java.io.IOException;
+
+/**
+ * Launches the given activity
+ */
+public class ActivityLaunchAction implements IAndroidLaunchAction {
+
+    private final String mActivity;
+    private final ILaunchController mLaunchController;
+    
+    /**
+     * Creates a ActivityLaunchAction
+     * 
+     * @param activity fully qualified activity name to launch
+     * @param controller the {@link ILaunchController} that performs launch
+     */
+    public ActivityLaunchAction(String activity, ILaunchController controller) {
+        mActivity = activity;
+        mLaunchController = controller;
+    }
+    
+    /**
+     * Launches the activity on targeted device
+     * 
+     * @param info the {@link DelayedLaunchInfo} that contains launch details
+     * @param device the Android device to perform action on
+     * 
+     * @see IAndroidLaunchAction#doLaunchAction(DelayedLaunchInfo, IDevice)
+     */
+    public boolean doLaunchAction(DelayedLaunchInfo info, IDevice device) {
+        try {
+            String msg = String.format("Starting activity %1$s on device ", mActivity,
+                    device);
+            AdtPlugin.printToConsole(info.getProject(), msg);
+
+            // In debug mode, we need to add the info to the list of application monitoring
+            // client changes.
+            // increment launch attempt count, to handle retries and timeouts
+            info.incrementAttemptCount();
+
+            // now we actually launch the app.
+            device.executeShellCommand("am start" //$NON-NLS-1$
+                    + (info.isDebugMode() ? " -D" //$NON-NLS-1$
+                            : "") //$NON-NLS-1$
+                    + " -n " //$NON-NLS-1$
+                    + info.getPackageName() + "/" //$NON-NLS-1$
+                    + mActivity.replaceAll("\\$", "\\\\\\$"), //$NON-NLS-1$ //$NON-NLS-2$
+                    new AMReceiver(info, device, mLaunchController));
+
+            // if the app is not a debug app, we need to do some clean up, as
+            // the process is done!
+            if (info.isDebugMode() == false) {
+                // stop the launch object, since there's no debug, and it can't
+                // provide any control over the app
+                return false;
+            }
+        } catch (IOException e) {
+            // something went wrong trying to launch the app.
+            // lets stop the Launch
+            AdtPlugin.printErrorToConsole(info.getProject(),
+                    String.format("Launch error: %s", e.getMessage()));
+            return false;
+        }
+        return true;
+    }
+    
+    /**
+     * Returns a description of the activity being launched
+     * 
+     * @see IAndroidLaunchAction#getLaunchDescription()
+     */
+    public String getLaunchDescription() {
+       return String.format("%1$s activity launch", mActivity);
+    }
+    
+}
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunch.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunch.java
index 7029206..42927c2 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunch.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunch.java
@@ -26,7 +26,7 @@
  * Custom implementation of Launch to allow access to the LaunchManager
  *
  */
-class AndroidLaunch extends Launch {
+public class AndroidLaunch extends Launch {
 
     /**
      * Basic constructor does nothing special
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchConfiguration.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchConfiguration.java
new file mode 100644
index 0000000..448cda6
--- /dev/null
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchConfiguration.java
@@ -0,0 +1,133 @@
+/*
+ * 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.launch;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.ILaunchConfiguration;
+
+/**
+ * Launch configuration data. This stores the result of querying the
+ * {@link ILaunchConfiguration} so that it's only done once. 
+ */
+public class AndroidLaunchConfiguration {
+    
+    /**
+     * Launch action. See {@link LaunchConfigDelegate#ACTION_DEFAULT},
+     * {@link LaunchConfigDelegate#ACTION_ACTIVITY},
+     * {@link LaunchConfigDelegate#ACTION_DO_NOTHING}
+     */
+    public int mLaunchAction = LaunchConfigDelegate.DEFAULT_LAUNCH_ACTION;
+    
+    public static final boolean AUTO_TARGET_MODE = true;
+
+    /**
+     * Target selection mode.
+     * <ul>
+     * <li><code>true</code>: automatic mode, see {@link #AUTO_TARGET_MODE}</li>
+     * <li><code>false</code>: manual mode</li>
+     * </ul>
+     */
+    public boolean mTargetMode = LaunchConfigDelegate.DEFAULT_TARGET_MODE;
+
+    /**
+     * Indicates whether the emulator should be called with -wipe-data
+     */
+    public boolean mWipeData = LaunchConfigDelegate.DEFAULT_WIPE_DATA;
+
+    /**
+     * Indicates whether the emulator should be called with -no-boot-anim
+     */
+    public boolean mNoBootAnim = LaunchConfigDelegate.DEFAULT_NO_BOOT_ANIM;
+    
+    /**
+     * AVD Name.
+     */
+    public String mAvdName = null;
+    
+    public String mNetworkSpeed = EmulatorConfigTab.getSpeed(
+            LaunchConfigDelegate.DEFAULT_SPEED);
+    public String mNetworkDelay = EmulatorConfigTab.getDelay(
+            LaunchConfigDelegate.DEFAULT_DELAY);
+
+    /**
+     * Optional custom command line parameter to launch the emulator
+     */
+    public String mEmulatorCommandLine;
+
+    /**
+     * Initialized the structure from an ILaunchConfiguration object.
+     * @param config
+     */
+    public void set(ILaunchConfiguration config) {
+        try {
+            mLaunchAction = config.getAttribute(LaunchConfigDelegate.ATTR_LAUNCH_ACTION,
+                    mLaunchAction);
+        } catch (CoreException e1) {
+            // nothing to be done here, we'll use the default value
+        }
+
+        try {
+            mTargetMode = config.getAttribute(LaunchConfigDelegate.ATTR_TARGET_MODE,
+                    mTargetMode);
+        } catch (CoreException e) {
+            // nothing to be done here, we'll use the default value
+        }
+
+        try {
+            mAvdName = config.getAttribute(LaunchConfigDelegate.ATTR_AVD_NAME, mAvdName);
+        } catch (CoreException e) {
+            // ignore
+        }
+
+        int index = LaunchConfigDelegate.DEFAULT_SPEED;
+        try {
+            index = config.getAttribute(LaunchConfigDelegate.ATTR_SPEED, index);
+        } catch (CoreException e) {
+            // nothing to be done here, we'll use the default value
+        }
+        mNetworkSpeed = EmulatorConfigTab.getSpeed(index);
+
+        index = LaunchConfigDelegate.DEFAULT_DELAY;
+        try {
+            index = config.getAttribute(LaunchConfigDelegate.ATTR_DELAY, index);
+        } catch (CoreException e) {
+            // nothing to be done here, we'll use the default value
+        }
+        mNetworkDelay = EmulatorConfigTab.getDelay(index);
+
+        try {
+            mEmulatorCommandLine = config.getAttribute(
+                    LaunchConfigDelegate.ATTR_COMMANDLINE, ""); //$NON-NLS-1$
+        } catch (CoreException e) {
+            // lets not do anything here, we'll use the default value
+        }
+
+        try {
+            mWipeData = config.getAttribute(LaunchConfigDelegate.ATTR_WIPE_DATA, mWipeData);
+        } catch (CoreException e) {
+            // nothing to be done here, we'll use the default value
+        }
+
+        try {
+            mNoBootAnim = config.getAttribute(LaunchConfigDelegate.ATTR_NO_BOOT_ANIM,
+                                              mNoBootAnim);
+        } catch (CoreException e) {
+            // nothing to be done here, we'll use the default value
+        }
+    }
+}
+
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchController.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchController.java
index 111d6b3..88ee8b6 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchController.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchController.java
@@ -17,17 +17,19 @@
 package com.android.ide.eclipse.adt.launch;
 
 import com.android.ddmlib.AndroidDebugBridge;
-import com.android.ddmlib.Client;
-import com.android.ddmlib.ClientData;
-import com.android.ddmlib.Device;
-import com.android.ddmlib.Log;
-import com.android.ddmlib.MultiLineReceiver;
-import com.android.ddmlib.SyncService;
 import com.android.ddmlib.AndroidDebugBridge.IClientChangeListener;
 import com.android.ddmlib.AndroidDebugBridge.IDebugBridgeChangeListener;
 import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener;
+import com.android.ddmlib.Client;
+import com.android.ddmlib.ClientData;
+import com.android.ddmlib.Device;
+import com.android.ddmlib.IDevice;
+import com.android.ddmlib.Log;
+import com.android.ddmlib.MultiLineReceiver;
+import com.android.ddmlib.SyncService;
 import com.android.ddmlib.SyncService.SyncResult;
 import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.launch.DelayedLaunchInfo.InstallRetryMode;
 import com.android.ide.eclipse.adt.launch.DeviceChooserDialog.DeviceChooserResponse;
 import com.android.ide.eclipse.adt.project.ProjectHelper;
 import com.android.ide.eclipse.adt.sdk.Sdk;
@@ -72,7 +74,7 @@
  * it.
  */
 public final class AndroidLaunchController implements IDebugBridgeChangeListener,
-        IDeviceChangeListener, IClientChangeListener {
+        IDeviceChangeListener, IClientChangeListener, ILaunchController {
     
     private static final String FLAG_AVD = "-avd"; //$NON-NLS-1$
     private static final String FLAG_NETDELAY = "-netdelay"; //$NON-NLS-1$
@@ -80,83 +82,15 @@
     private static final String FLAG_WIPE_DATA = "-wipe-data"; //$NON-NLS-1$
     private static final String FLAG_NO_BOOT_ANIM = "-no-boot-anim"; //$NON-NLS-1$
 
-    private static final int MAX_ATTEMPT_COUNT = 5;
-
-    private final static Pattern sAmErrorType = Pattern.compile("Error type (\\d+)"); //$NON-NLS-1$
-
-    /**
-     * A delayed launch waiting for a device to be present or ready before the
-     * application is launched.
-     */
-    static final class DelayedLaunchInfo {
-        /** The device on which to launch the app */
-        Device mDevice = null;
-
-        /** The eclipse project */
-        IProject mProject;
-
-        /** Package name */
-        String mPackageName;
-
-        /** fully qualified name of the activity */
-        String mActivity;
-
-        /** IFile to the package (.apk) file */
-        IFile mPackageFile;
-        
-        /** Debuggable attribute of the manifest file. */
-        Boolean mDebuggable = null;
-        
-        /** Required ApiVersionNumber by the app. 0 means no requirements */
-        int mRequiredApiVersionNumber = 0;
-        
-        InstallRetryMode mRetryMode = InstallRetryMode.NEVER;
-        
-        /**
-         * Launch action. See {@link LaunchConfigDelegate#ACTION_DEFAULT},
-         * {@link LaunchConfigDelegate#ACTION_ACTIVITY},
-         * {@link LaunchConfigDelegate#ACTION_DO_NOTHING}
-         */
-        int mLaunchAction;
-
-        /** the launch object */
-        AndroidLaunch mLaunch;
-
-        /** the monitor object */
-        IProgressMonitor mMonitor;
-
-        /** debug mode flag */
-        boolean mDebugMode;
-
-        int mAttemptCount = 0;
-
-        boolean mCancelled = false;
-
-        /** Basic constructor with activity and package info. */
-        private DelayedLaunchInfo(IProject project, String packageName, String activity,
-                IFile pack, Boolean debuggable, int requiredApiVersionNumber, int launchAction,
-                AndroidLaunch launch, IProgressMonitor monitor) {
-            mProject = project;
-            mPackageName = packageName;
-            mActivity = activity;
-            mPackageFile = pack;
-            mLaunchAction = launchAction;
-            mLaunch = launch;
-            mMonitor = monitor;
-            mDebuggable = debuggable;
-            mRequiredApiVersionNumber = requiredApiVersionNumber;
-        }
-    }
-    
     /**
      * Map to store {@link ILaunchConfiguration} objects that must be launched as simple connection
      * to running application. The integer is the port on which to connect. 
      * <b>ALL ACCESS MUST BE INSIDE A <code>synchronized (sListLock)</code> block!</b>
      */
-    private final static HashMap<ILaunchConfiguration, Integer> sRunningAppMap =
+    private static final HashMap<ILaunchConfiguration, Integer> sRunningAppMap =
         new HashMap<ILaunchConfiguration, Integer>();
 
-    private final static Object sListLock = sRunningAppMap;
+    private static final Object sListLock = sRunningAppMap;
 
     /**
      * List of {@link DelayedLaunchInfo} waiting for an emulator to connect.
@@ -190,243 +124,15 @@
     /** static instance for singleton */
     private static AndroidLaunchController sThis = new AndroidLaunchController();
     
-    enum InstallRetryMode {
-        NEVER, ALWAYS, PROMPT;  
-    }
 
-    /**
-     * Launch configuration data. This stores the result of querying the
-     * {@link ILaunchConfiguration} so that it's only done once. 
-     */
-    static final class AndroidLaunchConfiguration {
-        
-        /**
-         * Launch action. See {@link LaunchConfigDelegate#ACTION_DEFAULT},
-         * {@link LaunchConfigDelegate#ACTION_ACTIVITY},
-         * {@link LaunchConfigDelegate#ACTION_DO_NOTHING}
-         */
-        public int mLaunchAction = LaunchConfigDelegate.DEFAULT_LAUNCH_ACTION;
-        
-        public static final boolean AUTO_TARGET_MODE = true;
-
-        /**
-         * Target selection mode.
-         * <ul>
-         * <li><code>true</code>: automatic mode, see {@link #AUTO_TARGET_MODE}</li>
-         * <li><code>false</code>: manual mode</li>
-         * </ul>
-         */
-        public boolean mTargetMode = LaunchConfigDelegate.DEFAULT_TARGET_MODE;
-
-        /**
-         * Indicates whether the emulator should be called with -wipe-data
-         */
-        public boolean mWipeData = LaunchConfigDelegate.DEFAULT_WIPE_DATA;
-
-        /**
-         * Indicates whether the emulator should be called with -no-boot-anim
-         */
-        public boolean mNoBootAnim = LaunchConfigDelegate.DEFAULT_NO_BOOT_ANIM;
-        
-        /**
-         * AVD Name.
-         */
-        public String mAvdName = null;
-        
-        public String mNetworkSpeed = EmulatorConfigTab.getSpeed(
-                LaunchConfigDelegate.DEFAULT_SPEED);
-        public String mNetworkDelay = EmulatorConfigTab.getDelay(
-                LaunchConfigDelegate.DEFAULT_DELAY);
-
-        /**
-         * Optional custom command line parameter to launch the emulator
-         */
-        public String mEmulatorCommandLine;
-
-        /**
-         * Initialized the structure from an ILaunchConfiguration object.
-         * @param config
-         */
-        public void set(ILaunchConfiguration config) {
-            try {
-                mLaunchAction = config.getAttribute(LaunchConfigDelegate.ATTR_LAUNCH_ACTION,
-                        mLaunchAction);
-            } catch (CoreException e1) {
-                // nothing to be done here, we'll use the default value
-            }
-
-            try {
-                mTargetMode = config.getAttribute(LaunchConfigDelegate.ATTR_TARGET_MODE,
-                        mTargetMode);
-            } catch (CoreException e) {
-                // nothing to be done here, we'll use the default value
-            }
-
-            try {
-                mAvdName = config.getAttribute(LaunchConfigDelegate.ATTR_AVD_NAME, mAvdName);
-            } catch (CoreException e) {
-            }
-
-            int index = LaunchConfigDelegate.DEFAULT_SPEED;
-            try {
-                index = config.getAttribute(LaunchConfigDelegate.ATTR_SPEED, index);
-            } catch (CoreException e) {
-                // nothing to be done here, we'll use the default value
-            }
-            mNetworkSpeed = EmulatorConfigTab.getSpeed(index);
-
-            index = LaunchConfigDelegate.DEFAULT_DELAY;
-            try {
-                index = config.getAttribute(LaunchConfigDelegate.ATTR_DELAY, index);
-            } catch (CoreException e) {
-                // nothing to be done here, we'll use the default value
-            }
-            mNetworkDelay = EmulatorConfigTab.getDelay(index);
-
-            try {
-                mEmulatorCommandLine = config.getAttribute(
-                        LaunchConfigDelegate.ATTR_COMMANDLINE, ""); //$NON-NLS-1$
-            } catch (CoreException e) {
-                // lets not do anything here, we'll use the default value
-            }
-
-            try {
-                mWipeData = config.getAttribute(LaunchConfigDelegate.ATTR_WIPE_DATA, mWipeData);
-            } catch (CoreException e) {
-                // nothing to be done here, we'll use the default value
-            }
-
-            try {
-                mNoBootAnim = config.getAttribute(LaunchConfigDelegate.ATTR_NO_BOOT_ANIM,
-                                                  mNoBootAnim);
-            } catch (CoreException e) {
-                // nothing to be done here, we'll use the default value
-            }
-        }
-    }
-
-    /**
-     * Output receiver for am process (activity Manager);
-     */
-    private final class AMReceiver extends MultiLineReceiver {
-        private DelayedLaunchInfo mLaunchInfo;
-        private Device mDevice;
-
-        /**
-         * Basic constructor.
-         * @param launchInfo The launch info associated with the am process.
-         * @param device The device on which the launch is done.
-         */
-        public AMReceiver(DelayedLaunchInfo launchInfo, Device device) {
-            mLaunchInfo = launchInfo;
-            mDevice = device;
-        }
-
-        @Override
-        public void processNewLines(String[] lines) {
-            // first we check if one starts with error
-            ArrayList<String> array = new ArrayList<String>();
-            boolean error = false;
-            boolean warning = false;
-            for (String s : lines) {
-                // ignore empty lines.
-                if (s.length() == 0) {
-                    continue;
-                }
-
-                // check for errors that output an error type, if the attempt count is still
-                // valid. If not the whole text will be output in the console
-                if (mLaunchInfo.mAttemptCount < MAX_ATTEMPT_COUNT &&
-                        mLaunchInfo.mCancelled == false) {
-                    Matcher m = sAmErrorType.matcher(s);
-                    if (m.matches()) {
-                        // get the error type
-                        int type = Integer.parseInt(m.group(1));
-
-                        final int waitTime = 3;
-                        String msg;
-
-                        switch (type) {
-                            case 1:
-                                /* Intended fall through */
-                            case 2:
-                                msg = String.format(
-                                        "Device not ready. Waiting %1$d seconds before next attempt.",
-                                        waitTime);
-                                break;
-                            case 3:
-                                msg = String.format(
-                                        "New package not yet registered with the system. Waiting %1$d seconds before next attempt.",
-                                        waitTime);
-                                break;
-                            default:
-                                msg = String.format(
-                                        "Device not ready (%2$d). Waiting %1$d seconds before next attempt.",
-                                        waitTime, type);
-                                break;
-
-                        }
-
-                        AdtPlugin.printToConsole(mLaunchInfo.mProject, msg);
-
-                        // launch another thread, that waits a bit and attempts another launch
-                        new Thread("Delayed Launch attempt") {
-                            @Override
-                            public void run() {
-                                try {
-                                    sleep(waitTime * 1000);
-                                } catch (InterruptedException e) {
-                                }
-
-                                launchApp(mLaunchInfo, mDevice);
-                            }
-                        }.start();
-
-                        // no need to parse the rest
-                        return;
-                    }
-                }
-
-                // check for error if needed
-                if (error == false && s.startsWith("Error:")) { //$NON-NLS-1$
-                    error = true;
-                }
-                if (warning == false && s.startsWith("Warning:")) { //$NON-NLS-1$
-                    warning = true;
-                }
-
-                // add the line to the list
-                array.add("ActivityManager: " + s); //$NON-NLS-1$
-            }
-
-            // then we display them in the console
-            if (warning || error) {
-                AdtPlugin.printErrorToConsole(mLaunchInfo.mProject, array.toArray());
-            } else {
-                AdtPlugin.printToConsole(mLaunchInfo.mProject, array.toArray());
-            }
-
-            // if error then we cancel the launch, and remove the delayed info
-            if (error) {
-                mLaunchInfo.mLaunch.stopLaunch();
-                synchronized (sListLock) {
-                    mWaitingForReadyEmulatorList.remove(mLaunchInfo);
-                }
-            }
-        }
-
-        public boolean isCancelled() {
-            return false;
-        }
-    }
 
     /**
      * Output receiver for "pm install package.apk" command line.
      */
-    private final static class InstallReceiver extends MultiLineReceiver {
+    private static final class InstallReceiver extends MultiLineReceiver {
         
-        private final static String SUCCESS_OUTPUT = "Success"; //$NON-NLS-1$
-        private final static Pattern FAILURE_PATTERN = Pattern.compile("Failure\\s+\\[(.*)\\]"); //$NON-NLS-1$
+        private static final String SUCCESS_OUTPUT = "Success"; //$NON-NLS-1$
+        private static final Pattern FAILURE_PATTERN = Pattern.compile("Failure\\s+\\[(.*)\\]"); //$NON-NLS-1$
         
         private String mSuccess = null;
         
@@ -533,7 +239,7 @@
                         LaunchConfigDelegate.DEFAULT_TARGET_MODE);
 
                 // default AVD: None
-                wc.setAttribute(LaunchConfigDelegate.ATTR_AVD_NAME, (String)null);
+                wc.setAttribute(LaunchConfigDelegate.ATTR_AVD_NAME, (String) null);
 
                 // set the default network speed
                 wc.setAttribute(LaunchConfigDelegate.ATTR_SPEED,
@@ -602,30 +308,24 @@
      * @param apk the resource to the apk to launch.
      * @param debuggable the debuggable value of the app, or null if not set.
      * @param requiredApiVersionNumber the api version required by the app, or -1 if none.
-     * @param activity the class to provide to am to launch
+     * @param launchAction the action to perform after app sync
      * @param config the launch configuration
      * @param launch the launch object
      */
     public void launch(final IProject project, String mode, IFile apk,
-            String packageName, Boolean debuggable, int requiredApiVersionNumber, String activity,
-            final AndroidLaunchConfiguration config, final AndroidLaunch launch,
-            IProgressMonitor monitor) {
+            String packageName, Boolean debuggable, int requiredApiVersionNumber, 
+            final IAndroidLaunchAction launchAction, final AndroidLaunchConfiguration config, 
+            final AndroidLaunch launch, IProgressMonitor monitor) {
         
-        String message;
-        if (config.mLaunchAction == LaunchConfigDelegate.ACTION_DO_NOTHING) {
-            message = String.format("Only Syncing Application Package");
-        } else {
-            message = String.format("Launching: %1$s", activity);
-        }
+        String message = String.format("Performing %1$s", launchAction.getLaunchDescription());
         AdtPlugin.printToConsole(project, message);
 
         // create the launch info
         final DelayedLaunchInfo launchInfo = new DelayedLaunchInfo(project, packageName,
-                activity, apk, debuggable, requiredApiVersionNumber, config.mLaunchAction,
-                launch, monitor);
+                launchAction, apk, debuggable, requiredApiVersionNumber, launch, monitor);
 
         // set the debug mode
-        launchInfo.mDebugMode = mode.equals(ILaunchManager.DEBUG_MODE);
+        launchInfo.setDebugMode(mode.equals(ILaunchManager.DEBUG_MODE));
 
         // get the SDK
         Sdk currentSdk = Sdk.getCurrent();
@@ -657,7 +357,7 @@
         
         if (config.mTargetMode == AndroidLaunchConfiguration.AUTO_TARGET_MODE) {
             // if we are in automatic target mode, we need to find the current devices
-            Device[] devices = AndroidDebugBridge.getBridge().getDevices();
+            IDevice[] devices = AndroidDebugBridge.getBridge().getDevices();
             
             // first check if we have a preferred AVD name, and if it actually exists, and is valid
             // (ie able to run the project).
@@ -677,7 +377,7 @@
                 
             if (preferredAvd != null) {
                 // look for a matching device
-                for (Device d : devices) {
+                for (IDevice d : devices) {
                     String deviceAvd = d.getAvdName();
                     if (deviceAvd != null && deviceAvd.equals(config.mAvdName)) {
                         response.setDeviceToUse(d);
@@ -704,12 +404,12 @@
             }
 
             // no (valid) preferred AVD? look for one.
-            HashMap<Device, AvdInfo> compatibleRunningAvds = new HashMap<Device, AvdInfo>();
+            HashMap<IDevice, AvdInfo> compatibleRunningAvds = new HashMap<IDevice, AvdInfo>();
             boolean hasDevice = false; // if there's 1+ device running, we may force manual mode,
                                        // as we cannot always detect proper compatibility with
                                        // devices. This is the case if the project target is not
                                        // a standard platform
-            for (Device d : devices) {
+            for (IDevice d : devices) {
                 String deviceAvd = d.getAvdName();
                 if (deviceAvd != null) { // physical devices return null.
                     AvdInfo info = avdManager.getAvd(deviceAvd);
@@ -770,11 +470,11 @@
                     AdtPlugin.printErrorToConsole(project, String.format(
                             "Failed to find a AVD compatible with target '%1$s'. Launch aborted.",
                             projectTarget.getName()));
-                    launch.stopLaunch();
+                    stopLaunch(launchInfo);
                     return;
                 }
             } else if (hasDevice == false && compatibleRunningAvds.size() == 1) {
-                Entry<Device, AvdInfo> e = compatibleRunningAvds.entrySet().iterator().next();
+                Entry<IDevice, AvdInfo> e = compatibleRunningAvds.entrySet().iterator().next();
                 response.setDeviceToUse(e.getKey());
 
                 // get the AvdInfo, if null, the device is a physical device.
@@ -810,13 +510,13 @@
                     // or the AVD to launch.
                     DeviceChooserDialog dialog = new DeviceChooserDialog(
                             AdtPlugin.getDisplay().getActiveShell(),
-                            response, launchInfo.mPackageName, projectTarget);
+                            response, launchInfo.getPackageName(), projectTarget);
                     if (dialog.open() == Dialog.OK) {
                         AndroidLaunchController.this.continueLaunch(response, project, launch,
                                 launchInfo, config);
                     } else {
                         AdtPlugin.printErrorToConsole(project, "Launch canceled!");
-                        launch.stopLaunch();
+                        stopLaunch(launchInfo);
                         return;
                     }
                 } catch (Exception e) {
@@ -830,7 +530,7 @@
                     }
                     AdtPlugin.printErrorToConsole(project,
                             String.format("Error during launch: %s", msg));
-                    launch.stopLaunch();
+                    stopLaunch(launchInfo);
                 }
             }
         });
@@ -871,15 +571,15 @@
                             // stop the launch and return
                             mWaitingForEmulatorLaunches.remove(launchInfo);
                             AdtPlugin.printErrorToConsole(project, "Launch canceled!");
-                            launch.stopLaunch();
+                            stopLaunch(launchInfo);
                             return;
                         }
                         
                         return;
                     }
                 } else if (response.getDeviceToUse() != null) {
-                    launchInfo.mDevice = response.getDeviceToUse();
-                    simpleLaunch(launchInfo, launchInfo.mDevice);
+                    launchInfo.setDevice(response.getDeviceToUse());
+                    simpleLaunch(launchInfo, launchInfo.getDevice());
                 }
             }
         }.start();
@@ -932,12 +632,12 @@
      * "release" mode instead of "debug"</li>
      * <ul>
      */
-    private boolean checkBuildInfo(DelayedLaunchInfo launchInfo, Device device) {
+    private boolean checkBuildInfo(DelayedLaunchInfo launchInfo, IDevice device) {
         if (device != null) {
             // check the app required API level versus the target device API level
             
-            String deviceApiVersionName = device.getProperty(Device.PROP_BUILD_VERSION);
-            String value = device.getProperty(Device.PROP_BUILD_VERSION_NUMBER);
+            String deviceApiVersionName = device.getProperty(IDevice.PROP_BUILD_VERSION);
+            String value = device.getProperty(IDevice.PROP_BUILD_VERSION_NUMBER);
             int deviceApiVersionNumber = 0;
             try {
                 deviceApiVersionNumber = Integer.parseInt(value);
@@ -945,30 +645,30 @@
                 // pass, we'll keep the deviceVersionNumber value at 0.
             }
             
-            if (launchInfo.mRequiredApiVersionNumber == 0) {
+            if (launchInfo.getRequiredApiVersionNumber() == 0) {
                 // warn the API level requirement is not set.
-                AdtPlugin.printErrorToConsole(launchInfo.mProject,
+                AdtPlugin.printErrorToConsole(launchInfo.getProject(),
                         "WARNING: Application does not specify an API level requirement!");
 
                 // and display the target device API level (if known)
                 if (deviceApiVersionName == null || deviceApiVersionNumber == 0) {
-                    AdtPlugin.printErrorToConsole(launchInfo.mProject,
+                    AdtPlugin.printErrorToConsole(launchInfo.getProject(),
                             "WARNING: Unknown device API version!");
                 } else {
-                    AdtPlugin.printErrorToConsole(launchInfo.mProject, String.format(
+                    AdtPlugin.printErrorToConsole(launchInfo.getProject(), String.format(
                             "Device API version is %1$d (Android %2$s)", deviceApiVersionNumber,
                             deviceApiVersionName));
                 }
             } else { // app requires a specific API level
                 if (deviceApiVersionName == null || deviceApiVersionNumber == 0) {
-                    AdtPlugin.printToConsole(launchInfo.mProject,
+                    AdtPlugin.printToConsole(launchInfo.getProject(),
                             "WARNING: Unknown device API version!");
-                } else if (deviceApiVersionNumber < launchInfo.mRequiredApiVersionNumber) {
+                } else if (deviceApiVersionNumber < launchInfo.getRequiredApiVersionNumber()) {
                     String msg = String.format(
                             "ERROR: Application requires API version %1$d. Device API version is %2$d (Android %3$s).",
-                            launchInfo.mRequiredApiVersionNumber, deviceApiVersionNumber,
+                            launchInfo.getRequiredApiVersionNumber(), deviceApiVersionNumber,
                             deviceApiVersionName);
-                    AdtPlugin.printErrorToConsole(launchInfo.mProject, msg);
+                    AdtPlugin.printErrorToConsole(launchInfo.getProject(), msg);
                     
                     // abort the launch
                     return false;
@@ -976,33 +676,33 @@
             }
 
             // now checks that the device/app can be debugged (if needed)
-            if (device.isEmulator() == false && launchInfo.mDebugMode) {
-                String debuggableDevice = device.getProperty(Device.PROP_DEBUGGABLE);
+            if (device.isEmulator() == false && launchInfo.isDebugMode()) {
+                String debuggableDevice = device.getProperty(IDevice.PROP_DEBUGGABLE);
                 if (debuggableDevice != null && debuggableDevice.equals("0")) { //$NON-NLS-1$
                     // the device is "secure" and requires apps to declare themselves as debuggable!
-                    if (launchInfo.mDebuggable == null) {
+                    if (launchInfo.getDebuggable() == null) {
                         String message1 = String.format(
                                 "Device '%1$s' requires that applications explicitely declare themselves as debuggable in their manifest.",
                                 device.getSerialNumber());
                         String message2 = String.format("Application '%1$s' does not have the attribute 'debuggable' set to TRUE in its manifest and cannot be debugged.",
-                                launchInfo.mPackageName);
-                        AdtPlugin.printErrorToConsole(launchInfo.mProject, message1, message2);
+                                launchInfo.getPackageName());
+                        AdtPlugin.printErrorToConsole(launchInfo.getProject(), message1, message2);
                         
                         // because am -D does not check for ro.debuggable and the
                         // 'debuggable' attribute, it is important we do not use the -D option
                         // in this case or the app will wait for a debugger forever and never
                         // really launch.
-                        launchInfo.mDebugMode = false;
-                    } else if (launchInfo.mDebuggable == Boolean.FALSE) {
+                        launchInfo.setDebugMode(false);
+                    } else if (launchInfo.getDebuggable() == Boolean.FALSE) {
                         String message = String.format("Application '%1$s' has its 'debuggable' attribute set to FALSE and cannot be debugged.",
-                                launchInfo.mPackageName);
-                        AdtPlugin.printErrorToConsole(launchInfo.mProject, message);
+                                launchInfo.getPackageName());
+                        AdtPlugin.printErrorToConsole(launchInfo.getProject(), message);
 
                         // because am -D does not check for ro.debuggable and the
                         // 'debuggable' attribute, it is important we do not use the -D option
                         // in this case or the app will wait for a debugger forever and never
                         // really launch.
-                        launchInfo.mDebugMode = false;
+                        launchInfo.setDebugMode(false);
                     }
                 }
             }
@@ -1019,18 +719,18 @@
      * @param device
      * @return true if succeed
      */
-    private boolean simpleLaunch(DelayedLaunchInfo launchInfo, Device device) {
+    private boolean simpleLaunch(DelayedLaunchInfo launchInfo, IDevice device) {
         // API level check
         if (checkBuildInfo(launchInfo, device) == false) {
-            AdtPlugin.printErrorToConsole(launchInfo.mProject, "Launch canceled!");
-            launchInfo.mLaunch.stopLaunch();
+            AdtPlugin.printErrorToConsole(launchInfo.getProject(), "Launch canceled!");
+            stopLaunch(launchInfo);
             return false;
         }
 
         // sync the app
         if (syncApp(launchInfo, device) == false) {
-            AdtPlugin.printErrorToConsole(launchInfo.mProject, "Launch canceled!");
-            launchInfo.mLaunch.stopLaunch();
+            AdtPlugin.printErrorToConsole(launchInfo.getProject(), "Launch canceled!");
+            stopLaunch(launchInfo);
             return false;
         }
 
@@ -1048,16 +748,16 @@
      * @param device the device on which to sync the application
      * @return true if the install succeeded.
      */
-    private boolean syncApp(DelayedLaunchInfo launchInfo, Device device) {
+    private boolean syncApp(DelayedLaunchInfo launchInfo, IDevice device) {
         SyncService sync = device.getSyncService();
         if (sync != null) {
-            IPath path = launchInfo.mPackageFile.getLocation();
+            IPath path = launchInfo.getPackageFile().getLocation();
             String message = String.format("Uploading %1$s onto device '%2$s'",
                     path.lastSegment(), device.getSerialNumber());
-            AdtPlugin.printToConsole(launchInfo.mProject, message);
+            AdtPlugin.printToConsole(launchInfo.getProject(), message);
 
             String osLocalPath = path.toOSString();
-            String apkName = launchInfo.mPackageFile.getName();
+            String apkName = launchInfo.getPackageFile().getName();
             String remotePath = "/data/local/tmp/" + apkName; //$NON-NLS-1$
 
             SyncResult result = sync.pushFile(osLocalPath, remotePath,
@@ -1066,7 +766,7 @@
             if (result.getCode() != SyncService.RESULT_OK) {
                 String msg = String.format("Failed to upload %1$s on '%2$s': %3$s",
                         apkName, device.getSerialNumber(), result.getMessage());
-                AdtPlugin.printErrorToConsole(launchInfo.mProject, msg);
+                AdtPlugin.printErrorToConsole(launchInfo.getProject(), msg);
                 return false;
             }
 
@@ -1087,7 +787,7 @@
                     }
                 });
             } catch (IOException e) {
-                AdtPlugin.printErrorToConsole(launchInfo.mProject, String.format(
+                AdtPlugin.printErrorToConsole(launchInfo.getProject(), String.format(
                         "Failed to delete temporary package: %1$s", e.getMessage()));
                 return false;
             }
@@ -1097,8 +797,8 @@
 
         String msg = String.format(
                 "Failed to upload %1$s on device '%2$s': Unable to open sync connection!",
-                launchInfo.mPackageFile.getName(), device.getSerialNumber());
-        AdtPlugin.printErrorToConsole(launchInfo.mProject, msg);
+                launchInfo.getPackageFile().getName(), device.getSerialNumber());
+        AdtPlugin.printErrorToConsole(launchInfo.getProject(), msg);
 
         return false;
     }
@@ -1110,10 +810,10 @@
      * @param device The device on which the launch is done.
      */
     private boolean installPackage(DelayedLaunchInfo launchInfo, final String remotePath,
-            final Device device) {
+            final IDevice device) {
 
-        String message = String.format("Installing %1$s...", launchInfo.mPackageFile.getName());
-        AdtPlugin.printToConsole(launchInfo.mProject, message);
+        String message = String.format("Installing %1$s...", launchInfo.getPackageFile().getName());
+        AdtPlugin.printToConsole(launchInfo.getProject(), message);
 
         try {
             String result = doInstall(launchInfo, remotePath, device, false /* reinstall */);
@@ -1141,10 +841,10 @@
      * @return <code>true<code> if success, <code>false</code> otherwise.
      * @throws IOException
      */
-    private boolean checkInstallResult(String result, Device device, DelayedLaunchInfo launchInfo,
+    private boolean checkInstallResult(String result, IDevice device, DelayedLaunchInfo launchInfo,
             String remotePath, InstallRetryMode retryMode) throws IOException {
         if (result == null) {
-            AdtPlugin.printToConsole(launchInfo.mProject, "Success!");
+            AdtPlugin.printToConsole(launchInfo.getProject(), "Success!");
             return true;
         } else if (result.equals("INSTALL_FAILED_ALREADY_EXISTS")) { //$NON-NLS-1$
             if (retryMode == InstallRetryMode.PROMPT) {
@@ -1153,7 +853,7 @@
                 if (prompt) {
                     retryMode = InstallRetryMode.ALWAYS;
                 } else {
-                    AdtPlugin.printErrorToConsole(launchInfo.mProject,
+                    AdtPlugin.printErrorToConsole(launchInfo.getProject(),
                         "Installation error! The package already exists.");
                     return false;
                 }
@@ -1178,35 +878,35 @@
                 }
                 */
 
-                AdtPlugin.printToConsole(launchInfo.mProject,
+                AdtPlugin.printToConsole(launchInfo.getProject(),
                         "Application already exists. Attempting to re-install instead...");
                 String res = doInstall(launchInfo, remotePath, device, true /* reinstall */);
                 return checkInstallResult(res, device, launchInfo, remotePath,
                         InstallRetryMode.NEVER);
             }
 
-            AdtPlugin.printErrorToConsole(launchInfo.mProject,
+            AdtPlugin.printErrorToConsole(launchInfo.getProject(),
                     "Installation error! The package already exists.");
         } else if (result.equals("INSTALL_FAILED_INVALID_APK")) { //$NON-NLS-1$
-            AdtPlugin.printErrorToConsole(launchInfo.mProject,
+            AdtPlugin.printErrorToConsole(launchInfo.getProject(),
                 "Installation failed due to invalid APK file!",
                 "Please check logcat output for more details.");
         } else if (result.equals("INSTALL_FAILED_INVALID_URI")) { //$NON-NLS-1$
-            AdtPlugin.printErrorToConsole(launchInfo.mProject,
+            AdtPlugin.printErrorToConsole(launchInfo.getProject(),
                 "Installation failed due to invalid URI!",
                 "Please check logcat output for more details.");
         } else if (result.equals("INSTALL_FAILED_COULDNT_COPY")) { //$NON-NLS-1$
-            AdtPlugin.printErrorToConsole(launchInfo.mProject,
+            AdtPlugin.printErrorToConsole(launchInfo.getProject(),
                 String.format("Installation failed: Could not copy %1$s to its final location!",
-                        launchInfo.mPackageFile.getName()),
+                        launchInfo.getPackageFile().getName()),
                 "Please check logcat output for more details.");
         } else if (result.equals("INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES")) {
-            AdtPlugin.printErrorToConsole(launchInfo.mProject,
+            AdtPlugin.printErrorToConsole(launchInfo.getProject(),
                     "Re-installation failed due to different application signatures.",
                     "You must perform a full uninstall of the application. WARNING: This will remove the application data!",
-                    String.format("Please execute 'adb uninstall %1$s' in a shell.", launchInfo.mPackageName));
+                    String.format("Please execute 'adb uninstall %1$s' in a shell.", launchInfo.getPackageName()));
         } else {
-            AdtPlugin.printErrorToConsole(launchInfo.mProject,
+            AdtPlugin.printErrorToConsole(launchInfo.getProject(),
                 String.format("Installation error: %1$s", result),
                 "Please check logcat output for more details.");
         }
@@ -1222,15 +922,15 @@
      * @throws IOException 
      */
     @SuppressWarnings("unused")
-    private String doUninstall(Device device, DelayedLaunchInfo launchInfo) throws IOException {
+    private String doUninstall(IDevice device, DelayedLaunchInfo launchInfo) throws IOException {
         InstallReceiver receiver = new InstallReceiver();
         try {
-            device.executeShellCommand("pm uninstall " + launchInfo.mPackageName, //$NON-NLS-1$
+            device.executeShellCommand("pm uninstall " + launchInfo.getPackageName(), //$NON-NLS-1$
                     receiver);
         } catch (IOException e) {
             String msg = String.format(
-                    "Failed to uninstall %1$s: %2$s", launchInfo.mPackageName, e.getMessage());
-            AdtPlugin.printErrorToConsole(launchInfo.mProject, msg);
+                    "Failed to uninstall %1$s: %2$s", launchInfo.getPackageName(), e.getMessage());
+            AdtPlugin.printErrorToConsole(launchInfo.getProject(), msg);
             throw e;
         }
         
@@ -1248,9 +948,9 @@
      * @throws IOException 
      */
     private String doInstall(DelayedLaunchInfo launchInfo, final String remotePath,
-            final Device device, boolean reinstall) throws IOException {
+            final IDevice device, boolean reinstall) throws IOException {
         // kill running application
-        Client application = device.getClient(launchInfo.mPackageName);
+        Client application = device.getClient(launchInfo.getPackageName());
         if (application != null) {
             application.kill();
         }
@@ -1264,8 +964,9 @@
         } catch (IOException e) {
             String msg = String.format(
                     "Failed to install %1$s on device '%2$s': %3$s",
-                    launchInfo.mPackageFile.getName(), device.getSerialNumber(), e.getMessage());
-            AdtPlugin.printErrorToConsole(launchInfo.mProject, msg);
+                    launchInfo.getPackageFile().getName(), device.getSerialNumber(), 
+                    e.getMessage());
+            AdtPlugin.printErrorToConsole(launchInfo.getProject(), msg);
             throw e;
         }
         
@@ -1275,63 +976,29 @@
     /**
      * launches an application on a device or emulator
      *
-     * @param info the {@link DelayedLaunchInfo} that indicates the activity to launch
+     * @param info the {@link DelayedLaunchInfo} that indicates the launch action
      * @param device the device or emulator to launch the application on
      */
-    private void launchApp(final DelayedLaunchInfo info, Device device) {
-        // if we're not supposed to do anything, just stop the Launch item and return;
-        if (info.mLaunchAction == LaunchConfigDelegate.ACTION_DO_NOTHING) {
-            String msg = String.format("%1$s installed on device",
-                    info.mPackageFile.getFullPath().toOSString());
-            AdtPlugin.printToConsole(info.mProject, msg, "Done!");
-            info.mLaunch.stopLaunch();
-            return;
-        }
-        try {
-            String msg = String.format("Starting activity %1$s on device ", info.mActivity,
-                    info.mDevice);
-            AdtPlugin.printToConsole(info.mProject, msg);
-
-            // In debug mode, we need to add the info to the list of application monitoring
-            // client changes.
-            if (info.mDebugMode) {
-                synchronized (sListLock) {
-                    if (mWaitingForDebuggerApplications.contains(info) == false) {
-                        mWaitingForDebuggerApplications.add(info);
-                    }
+    public void launchApp(final DelayedLaunchInfo info, IDevice device) {
+        if (info.isDebugMode()) {
+            synchronized (sListLock) {
+                if (mWaitingForDebuggerApplications.contains(info) == false) {
+                    mWaitingForDebuggerApplications.add(info);
                 }
             }
-
-            // increment launch attempt count, to handle retries and timeouts
-            info.mAttemptCount++;
-
-            // now we actually launch the app.
-            device.executeShellCommand("am start" //$NON-NLS-1$
-                    + (info.mDebugMode ? " -D" //$NON-NLS-1$
-                            : "") //$NON-NLS-1$
-                    + " -n " //$NON-NLS-1$
-                    + info.mPackageName + "/" //$NON-NLS-1$
-                    + info.mActivity.replaceAll("\\$", "\\\\\\$"), //$NON-NLS-1$ //$NON-NLS-2$
-                    new AMReceiver(info, device));
-
+        }
+        if (info.getLaunchAction().doLaunchAction(info, device)) {
             // if the app is not a debug app, we need to do some clean up, as
             // the process is done!
-            if (info.mDebugMode == false) {
+            if (info.isDebugMode() == false) {
                 // stop the launch object, since there's no debug, and it can't
                 // provide any control over the app
-                info.mLaunch.stopLaunch();
+                stopLaunch(info);
             }
-        } catch (IOException e) {
-            // something went wrong trying to launch the app.
+        } else {
+            // something went wrong or no further launch action needed
             // lets stop the Launch
-            AdtPlugin.printErrorToConsole(info.mProject,
-                    String.format("Launch error: %s", e.getMessage()));
-            info.mLaunch.stopLaunch();
-
-            // and remove it from the list of app waiting for debuggers
-            synchronized (sListLock) {
-                mWaitingForDebuggerApplications.remove(info);
-            }
+            stopLaunch(info);
         }
     }
 
@@ -1339,7 +1006,7 @@
 
         // split the custom command line in segments
         ArrayList<String> customArgs = new ArrayList<String>();
-        boolean has_wipe_data = false;
+        boolean hasWipeData = false;
         if (config.mEmulatorCommandLine != null && config.mEmulatorCommandLine.length() > 0) {
             String[] segments = config.mEmulatorCommandLine.split("\\s+"); //$NON-NLS-1$
 
@@ -1347,17 +1014,17 @@
             for (String s : segments) {
                 if (s.length() > 0) {
                     customArgs.add(s);
-                    if (!has_wipe_data && s.equals(FLAG_WIPE_DATA)) {
-                        has_wipe_data = true;
+                    if (!hasWipeData && s.equals(FLAG_WIPE_DATA)) {
+                        hasWipeData = true;
                     }
                 }
             }
         }
 
-        boolean needs_wipe_data = config.mWipeData && !has_wipe_data;
-        if (needs_wipe_data) {
+        boolean needsWipeData = config.mWipeData && !hasWipeData;
+        if (needsWipeData) {
             if (!AdtPlugin.displayPrompt("Android Launch", "Are you sure you want to wipe all user data when starting this emulator?")) {
-                needs_wipe_data = false;
+                needsWipeData = false;
             }
         }
         
@@ -1378,7 +1045,7 @@
             list.add(config.mNetworkDelay);
         }
         
-        if (needs_wipe_data) {
+        if (needsWipeData) {
             list.add(FLAG_WIPE_DATA);
         }
 
@@ -1482,7 +1149,7 @@
      * @param monitor A Progress monitor
      * @see #connectRemoteDebugger(int, AndroidLaunch, IProgressMonitor)
      */
-    public static void launchRemoteDebugger( final int debugPort, final AndroidLaunch androidLaunch,
+    public static void launchRemoteDebugger(final int debugPort, final AndroidLaunch androidLaunch,
             final IProgressMonitor monitor) {
         new Thread("Debugger connection") { //$NON-NLS-1$
             @Override
@@ -1507,26 +1174,18 @@
      */
     public void bridgeChanged(AndroidDebugBridge bridge) {
         // The adb server has changed. We cancel any pending launches.
-        String message1 = "adb server change: cancelling '%1$s' launch!";
-        String message2 = "adb server change: cancelling sync!";
+        String message = "adb server change: cancelling '%1$s'!";
         synchronized (sListLock) {
             for (DelayedLaunchInfo launchInfo : mWaitingForReadyEmulatorList) {
-                if (launchInfo.mLaunchAction == LaunchConfigDelegate.ACTION_DO_NOTHING) {
-                    AdtPlugin.printErrorToConsole(launchInfo.mProject, message2);
-                } else {
-                    AdtPlugin.printErrorToConsole(launchInfo.mProject,
-                            String.format(message1, launchInfo.mActivity));
-                }
-                launchInfo.mLaunch.stopLaunch();
+                AdtPlugin.printErrorToConsole(launchInfo.getProject(),
+                    String.format(message, launchInfo.getLaunchAction().getLaunchDescription()));
+                stopLaunch(launchInfo);
             }
             for (DelayedLaunchInfo launchInfo : mWaitingForDebuggerApplications) {
-                if (launchInfo.mLaunchAction == LaunchConfigDelegate.ACTION_DO_NOTHING) {
-                    AdtPlugin.printErrorToConsole(launchInfo.mProject, message2);
-                } else {
-                    AdtPlugin.printErrorToConsole(launchInfo.mProject,
-                            String.format(message1, launchInfo.mActivity));
-                }
-                launchInfo.mLaunch.stopLaunch();
+                AdtPlugin.printErrorToConsole(launchInfo.getProject(),
+                        String.format(message, 
+                                launchInfo.getLaunchAction().getLaunchDescription()));
+                stopLaunch(launchInfo);
             }
 
             mWaitingForReadyEmulatorList.clear();
@@ -1552,15 +1211,15 @@
                 mWaitingForEmulatorLaunches.remove(0);
 
                 // give the launch item its device for later use.
-                launchInfo.mDevice = device;
+                launchInfo.setDevice(device);
 
                 // and move it to the other list
                 mWaitingForReadyEmulatorList.add(launchInfo);
                 
                 // and tell the user about it
-                AdtPlugin.printToConsole(launchInfo.mProject,
+                AdtPlugin.printToConsole(launchInfo.getProject(),
                         String.format("New emulator found: %1$s", device.getSerialNumber()));
-                AdtPlugin.printToConsole(launchInfo.mProject,
+                AdtPlugin.printToConsole(launchInfo.getProject(),
                         String.format("Waiting for HOME ('%1$s') to be launched...",
                             AdtPlugin.getDefault().getPreferenceStore().getString(
                                     AdtPlugin.PREFS_HOME_PACKAGE)));
@@ -1579,25 +1238,25 @@
     @SuppressWarnings("unchecked")
     public void deviceDisconnected(Device device) {
         // any pending launch on this device must be canceled.
-        String message = "%1$s disconnected! Cancelling '%2$s' launch!";
+        String message = "%1$s disconnected! Cancelling '%2$s'!";
         synchronized (sListLock) {
             ArrayList<DelayedLaunchInfo> copyList =
-                (ArrayList<DelayedLaunchInfo>)mWaitingForReadyEmulatorList.clone();
+                (ArrayList<DelayedLaunchInfo>) mWaitingForReadyEmulatorList.clone();
             for (DelayedLaunchInfo launchInfo : copyList) {
-                if (launchInfo.mDevice == device) {
-                    AdtPlugin.printErrorToConsole(launchInfo.mProject,
-                            String.format(message, device.getSerialNumber(), launchInfo.mActivity));
-                    launchInfo.mLaunch.stopLaunch();
-                    mWaitingForReadyEmulatorList.remove(launchInfo);
+                if (launchInfo.getDevice() == device) {
+                    AdtPlugin.printErrorToConsole(launchInfo.getProject(),
+                            String.format(message, device.getSerialNumber(), 
+                                    launchInfo.getLaunchAction().getLaunchDescription()));
+                    stopLaunch(launchInfo);
                 }
             }
-            copyList = (ArrayList<DelayedLaunchInfo>)mWaitingForDebuggerApplications.clone();
+            copyList = (ArrayList<DelayedLaunchInfo>) mWaitingForDebuggerApplications.clone();
             for (DelayedLaunchInfo launchInfo : copyList) {
-                if (launchInfo.mDevice == device) {
-                    AdtPlugin.printErrorToConsole(launchInfo.mProject,
-                            String.format(message, device.getSerialNumber(), launchInfo.mActivity));
-                    launchInfo.mLaunch.stopLaunch();
-                    mWaitingForDebuggerApplications.remove(launchInfo);
+                if (launchInfo.getDevice() == device) {
+                    AdtPlugin.printErrorToConsole(launchInfo.getProject(),
+                            String.format(message, device.getSerialNumber(), 
+                                    launchInfo.getLaunchAction().getLaunchDescription()));
+                    stopLaunch(launchInfo);
                 }
             }
         }
@@ -1641,13 +1300,13 @@
                 if (home.equals(applicationName)) {
                     
                     // looks like home is up, get its device
-                    Device device = client.getDevice();
+                    IDevice device = client.getDevice();
                     
                     // look for application waiting for home
                     synchronized (sListLock) {
-                        for (int i = 0 ; i < mWaitingForReadyEmulatorList.size() ;) {
+                        for (int i = 0; i < mWaitingForReadyEmulatorList.size(); ) {
                             DelayedLaunchInfo launchInfo = mWaitingForReadyEmulatorList.get(i);
-                            if (launchInfo.mDevice == device) {
+                            if (launchInfo.getDevice() == device) {
                                 // it's match, remove from the list
                                 mWaitingForReadyEmulatorList.remove(i);
                                 
@@ -1657,13 +1316,13 @@
                                 // so we check now
                                 if (checkBuildInfo(launchInfo, device) == false) {
                                     // device is not the proper API!
-                                    AdtPlugin.printErrorToConsole(launchInfo.mProject,
+                                    AdtPlugin.printErrorToConsole(launchInfo.getProject(),
                                             "Launch canceled!");
-                                    launchInfo.mLaunch.stopLaunch();
+                                    stopLaunch(launchInfo);
                                     return;
                                 }
         
-                                AdtPlugin.printToConsole(launchInfo.mProject,
+                                AdtPlugin.printToConsole(launchInfo.getProject(),
                                         String.format("HOME is up on device '%1$s'",
                                                 device.getSerialNumber()));
                                 
@@ -1673,9 +1332,9 @@
                                     launchApp(launchInfo, device);
                                 } else {
                                     // failure! Cancel and return
-                                    AdtPlugin.printErrorToConsole(launchInfo.mProject,
+                                    AdtPlugin.printErrorToConsole(launchInfo.getProject(),
                                     "Launch canceled!");
-                                    launchInfo.mLaunch.stopLaunch();
+                                    stopLaunch(launchInfo);
                                 }
                                 
                                 break;
@@ -1727,18 +1386,18 @@
             String applicationName = client.getClientData().getClientDescription();
             Log.d("adt", "App Name: " + applicationName);
             synchronized (sListLock) {
-                for (int i = 0 ; i < mWaitingForDebuggerApplications.size() ;) {
+                for (int i = 0; i < mWaitingForDebuggerApplications.size(); ) {
                     final DelayedLaunchInfo launchInfo = mWaitingForDebuggerApplications.get(i);
-                    if (client.getDevice() == launchInfo.mDevice &&
-                            applicationName.equals(launchInfo.mPackageName)) {
+                    if (client.getDevice() == launchInfo.getDevice() &&
+                            applicationName.equals(launchInfo.getPackageName())) {
                         // this is a match. We remove the launch info from the list
                         mWaitingForDebuggerApplications.remove(i);
                         
                         // and connect the debugger.
                         String msg = String.format(
                                 "Attempting to connect debugger to '%1$s' on port %2$d",
-                                launchInfo.mPackageName, client.getDebuggerListenPort());
-                        AdtPlugin.printToConsole(launchInfo.mProject, msg);
+                                launchInfo.getPackageName(), client.getDebuggerListenPort());
+                        AdtPlugin.printToConsole(launchInfo.getProject(), msg);
                         
                         new Thread("Debugger Connection") { //$NON-NLS-1$
                             @Override
@@ -1746,18 +1405,19 @@
                                 try {
                                     if (connectRemoteDebugger(
                                             client.getDebuggerListenPort(),
-                                            launchInfo.mLaunch, launchInfo.mMonitor) == false) {
+                                            launchInfo.getLaunch(), 
+                                            launchInfo.getMonitor()) == false) {
                                         return;
                                     }
                                 } catch (CoreException e) {
                                     // well something went wrong.
-                                    AdtPlugin.printErrorToConsole(launchInfo.mProject,
+                                    AdtPlugin.printErrorToConsole(launchInfo.getProject(),
                                             String.format("Launch error: %s", e.getMessage()));
                                     // stop the launch
-                                    launchInfo.mLaunch.stopLaunch();
+                                    stopLaunch(launchInfo);
                                 }
 
-                                launchInfo.mMonitor.done();
+                                launchInfo.getMonitor().done();
                             }
                         }.start();
                         
@@ -1833,4 +1493,15 @@
         }.start();
     }
 
+    /* (non-Javadoc)
+     * @see com.android.ide.eclipse.adt.launch.ILaunchController#stopLaunch(com.android.ide.eclipse.adt.launch.AndroidLaunchController.DelayedLaunchInfo)
+     */
+    public void stopLaunch(DelayedLaunchInfo launchInfo) {
+        launchInfo.getLaunch().stopLaunch();
+        synchronized (sListLock) {
+            mWaitingForReadyEmulatorList.remove(launchInfo);
+            mWaitingForDebuggerApplications.remove(launchInfo);
+        }       
+    }
 }
+
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DelayedLaunchInfo.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DelayedLaunchInfo.java
new file mode 100644
index 0000000..a59518c
--- /dev/null
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DelayedLaunchInfo.java
@@ -0,0 +1,226 @@
+/*
+ * 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.launch;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import com.android.ddmlib.IDevice;
+
+/**
+ * A delayed launch waiting for a device to be present or ready before the
+ * application is launched.
+ */
+public final class DelayedLaunchInfo {
+    
+    /**
+     * Used to indicate behavior when Android app already exists 
+     */
+    enum InstallRetryMode {
+        NEVER, ALWAYS, PROMPT;  
+    }
+    
+    /** The device on which to launch the app */
+    private IDevice mDevice = null;
+
+    /** The eclipse project */
+    private final IProject mProject;
+
+    /** Package name */
+    private final String mPackageName;
+
+    /** IFile to the package (.apk) file */
+    private final IFile mPackageFile;
+    
+    /** debuggable attribute of the manifest file. */
+    private final Boolean mDebuggable;
+    
+    /** Required ApiVersionNumber by the app. 0 means no requirements */
+    private final int mRequiredApiVersionNumber;
+    
+    private InstallRetryMode mRetryMode = InstallRetryMode.NEVER;
+    
+    /** Launch action. */
+    private final IAndroidLaunchAction mLaunchAction;
+
+    /** the launch object */
+    private final AndroidLaunch mLaunch;
+
+    /** the monitor object */
+    private final IProgressMonitor mMonitor;
+
+    /** debug mode flag */
+    private boolean mDebugMode;
+
+    /** current number of launch attempts */
+    private int mAttemptCount = 0;
+
+    /** cancellation state of launch */
+    private boolean mCancelled = false;
+
+    /** 
+     * Basic constructor with activity and package info. 
+     * 
+     * @param project the eclipse project that corresponds to Android app
+     * @param packageName package name of Android app 
+     * @param launchAction action to perform after app install
+     * @param pack IFile to the package (.apk) file
+     * @param debuggable debuggable attribute of the app's manifest file.
+     * @param requiredApiVersionNumber required SDK version by the app. 0 means no requirements.
+     * @param launch the launch object
+     * @param monitor progress monitor for launch
+     */
+    public DelayedLaunchInfo(IProject project, String packageName, 
+            IAndroidLaunchAction launchAction, IFile pack, Boolean debuggable, 
+            int requiredApiVersionNumber, AndroidLaunch launch, IProgressMonitor monitor) {
+        mProject = project;
+        mPackageName = packageName;
+        mPackageFile = pack;
+        mLaunchAction = launchAction;
+        mLaunch = launch;
+        mMonitor = monitor;
+        mDebuggable = debuggable;
+        mRequiredApiVersionNumber = requiredApiVersionNumber;
+    }
+
+    /**
+     * @return the device on which to launch the app
+     */
+    public IDevice getDevice() {
+        return mDevice;
+    }
+    
+    /**
+     * Set the device on which to launch the app
+     */
+    public void setDevice(IDevice device) {
+        mDevice = device;
+    }
+
+    /**
+     * @return the eclipse project that corresponds to Android app
+     */
+    public IProject getProject() {
+        return mProject;
+    }
+
+    /**
+     * @return the package name of the Android app
+     */
+    public String getPackageName() {
+        return mPackageName;
+    }
+
+    /**
+     * @return the application package file
+     */
+    public IFile getPackageFile() {
+        return mPackageFile;
+    }
+
+    /**
+     * @return true if Android app is marked as debuggable in its manifest 
+     */
+    public Boolean getDebuggable() {
+        return mDebuggable;
+    }
+
+    /**
+     * @return the required api version number for the Android app
+     */
+    public int getRequiredApiVersionNumber() {
+        return mRequiredApiVersionNumber;
+    }
+
+    /**
+     * @param retryMode the install retry mode to set
+     */
+    public void setRetryMode(InstallRetryMode retryMode) {
+        this.mRetryMode = retryMode;
+    }
+
+    /**
+     * @return the installation retry mode
+     */
+    public InstallRetryMode getRetryMode() {
+        return mRetryMode;
+    }
+
+    /**
+     * @return the launch action
+     */
+    public IAndroidLaunchAction getLaunchAction() {
+        return mLaunchAction;
+    }
+
+    /**
+     * @return the launch
+     */
+    public AndroidLaunch getLaunch() {
+        return mLaunch;
+    }
+
+    /**
+     * @return the launch progress monitor 
+     */
+    public IProgressMonitor getMonitor() {
+        return mMonitor;
+    }
+
+    /**
+     * @param debugMode the debug mode to set
+     */
+    public void setDebugMode(boolean debugMode) {
+        this.mDebugMode = debugMode;
+    }
+
+    /**
+     * @return true if this is a debug launch
+     */
+    public boolean isDebugMode() {
+        return mDebugMode;
+    }
+
+    /**
+     * Increases the number of launch attempts
+     */
+    public void incrementAttemptCount() {
+        mAttemptCount++;
+    }
+
+    /**
+     * @return the number of launch attempts made
+     */
+    public int getAttemptCount() {
+        return mAttemptCount;
+    }
+
+    /**
+     * Set if launch has been cancelled 
+     */
+    public void setCancelled(boolean cancelled) {
+        this.mCancelled = cancelled;
+    }
+
+    /**
+     * @return true if launch has been cancelled
+     */
+    public boolean isCancelled() {
+        return mCancelled;
+    }
+}
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DeviceChooserDialog.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DeviceChooserDialog.java
index a960bda..13bb83a 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DeviceChooserDialog.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DeviceChooserDialog.java
@@ -231,9 +231,9 @@
     
     public static class DeviceChooserResponse {
         private AvdInfo mAvdToLaunch;
-        private Device mDeviceToUse;
+        private IDevice mDeviceToUse;
         
-        public void setDeviceToUse(Device d) {
+        public void setDeviceToUse(IDevice d) {
             mDeviceToUse = d;
             mAvdToLaunch = null;
         }
@@ -243,7 +243,7 @@
             mDeviceToUse = null;
         }
         
-        public Device getDeviceToUse() {
+        public IDevice getDeviceToUse() {
             return mDeviceToUse;
         }
         
@@ -737,3 +737,4 @@
         mDisableAvdSelectionChange = false;
     }
 }
+
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/EmptyLaunchAction.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/EmptyLaunchAction.java
new file mode 100644
index 0000000..02ae675
--- /dev/null
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/EmptyLaunchAction.java
@@ -0,0 +1,38 @@
+/*
+ * 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.launch;
+
+import com.android.ddmlib.IDevice;
+import com.android.ide.eclipse.adt.AdtPlugin;
+
+/**
+ * A launch action that does nothing after the application has been installed
+ */
+public class EmptyLaunchAction implements IAndroidLaunchAction {
+
+    public boolean doLaunchAction(DelayedLaunchInfo info, IDevice device) {
+        // we're not supposed to do anything, just return;
+        String msg = String.format("%1$s installed on device",
+                info.getPackageFile().getFullPath().toOSString());
+        AdtPlugin.printToConsole(info.getProject(), msg, "Done!");
+        // return false so launch controller will not wait for debugger to attach
+        return false;
+    }
+
+    public String getLaunchDescription() {
+        return "sync";
+    }
+}
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/IAndroidLaunchAction.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/IAndroidLaunchAction.java
new file mode 100644
index 0000000..2f3cb89
--- /dev/null
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/IAndroidLaunchAction.java
@@ -0,0 +1,42 @@
+/*
+ * 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.launch;
+
+import com.android.ddmlib.IDevice;
+import com.android.ide.eclipse.adt.launch.DelayedLaunchInfo;
+
+/**
+ * An action to perform after performing a launch of an Android application
+ */
+public interface IAndroidLaunchAction {
+
+    /** 
+     * Do the launch
+     * 
+     * @param info the {@link DelayedLaunchInfo} that contains launch details
+     * @param device the Android device to perform action on
+     * @returns true if launch was successfully, and controller should wait for debugger to attach
+     *     (if applicable)
+     */
+    boolean doLaunchAction(DelayedLaunchInfo info, IDevice device);
+    
+    /**
+     * Return a description of launch, to be used for logging and error messages
+     */
+    String getLaunchDescription();
+    
+}
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/ILaunchController.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/ILaunchController.java
new file mode 100644
index 0000000..2372c2d
--- /dev/null
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/ILaunchController.java
@@ -0,0 +1,40 @@
+/*
+ * 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.launch;
+
+import com.android.ddmlib.IDevice;
+
+/**
+ * Interface for managing Android launches
+ */
+public interface ILaunchController {
+
+   /**
+    * Launches an application on a device or emulator
+    *
+    * @param launchInfo the {@link DelayedLaunchInfo} that indicates the launch action
+    * @param device the device or emulator to launch the application on
+    */
+    public void launchApp(DelayedLaunchInfo launchInfo, IDevice device);
+    
+    /**
+     * Cancels a launch
+     * 
+     * @param launchInfo the {@link DelayedLaunchInfo} to cancel
+     */
+    void stopLaunch(DelayedLaunchInfo launchInfo);
+}
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/LaunchConfigDelegate.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/LaunchConfigDelegate.java
index a46f56c..80f62ea 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/LaunchConfigDelegate.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/LaunchConfigDelegate.java
@@ -18,7 +18,6 @@
 
 import com.android.ddmlib.AndroidDebugBridge;
 import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.adt.launch.AndroidLaunchController.AndroidLaunchConfiguration;
 import com.android.ide.eclipse.adt.project.ProjectHelper;
 import com.android.ide.eclipse.common.AndroidConstants;
 import com.android.ide.eclipse.common.project.AndroidManifestParser;
@@ -233,7 +232,16 @@
             return;
         }
 
-        String activityName = null;
+        doLaunch(configuration, mode, monitor, project, androidLaunch, config, controller,
+                applicationPackage, manifestParser);
+    }
+
+    protected void doLaunch(ILaunchConfiguration configuration, String mode,
+            IProgressMonitor monitor, IProject project, AndroidLaunch androidLaunch,
+            AndroidLaunchConfiguration config, AndroidLaunchController controller,
+            IFile applicationPackage, AndroidManifestParser manifestParser) {
+        
+       String activityName = null;
         
         if (config.mLaunchAction == ACTION_ACTIVITY) { 
             // Get the activity name defined in the config
@@ -292,11 +300,16 @@
             }
         }
 
+        IAndroidLaunchAction launchAction = new EmptyLaunchAction();
+        if (activityName != null) {
+            launchAction = new ActivityLaunchAction(activityName, controller);
+        }
+
         // everything seems fine, we ask the launch controller to handle
         // the rest
         controller.launch(project, mode, applicationPackage, manifestParser.getPackage(),
                 manifestParser.getDebuggable(), manifestParser.getApiLevelRequirement(),
-                activityName, config, androidLaunch, monitor);
+                launchAction, config, androidLaunch, monitor);
     }
     
     @Override
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ProjectHelper.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ProjectHelper.java
index fd0c045..c650b98 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ProjectHelper.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ProjectHelper.java
@@ -400,6 +400,9 @@
                 try {
                     parser = AndroidManifestParser.parseForData(manifestFile);
                 } catch (CoreException e) {
+                    // ignore, handled below.
+                }
+                if (parser == null) {
                     // skip this project.
                     continue;
                 }
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java
index d686830..5aeb335 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java
@@ -253,8 +253,7 @@
             if (markerMessage != null) {
                 // log the error and put the marker on the project if we can.
                 if (outputToConsole) {
-                    AdtPlugin.printBuildToConsole(AdtConstants.BUILD_ALWAYS, iProject,
-                            markerMessage);
+                    AdtPlugin.printErrorToConsole(iProject, markerMessage);
                 }
                 
                 try {
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java
index 6c4f4ba..0dd88c0 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java
@@ -36,7 +36,6 @@
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.IWorkspace;
 import org.eclipse.core.resources.ResourcesPlugin;
-import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Path;
@@ -823,12 +822,7 @@
         Path path = new Path(f.getPath());
         String osPath = path.append(AndroidConstants.FN_ANDROID_MANIFEST).toOSString();
         
-        AndroidManifestParser manifestData = null;
-        try {
-            manifestData = AndroidManifestParser.parseForData(osPath);
-        } catch (CoreException e1) {
-            // ignore any parsing issue
-        }
+        AndroidManifestParser manifestData = AndroidManifestParser.parseForData(osPath);
         if (manifestData == null) {
             return;
         }
@@ -1096,10 +1090,8 @@
             }
 
             // Parse it and check the important fields.
-            AndroidManifestParser manifestData;
-            try {
-                manifestData = AndroidManifestParser.parseForData(osPath);
-            } catch (CoreException e) {
+            AndroidManifestParser manifestData = AndroidManifestParser.parseForData(osPath);
+            if (manifestData == null) {
                 return setStatus(
                         String.format("File %1$s could not be parsed.", osPath),
                         MSG_ERROR);
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 b2817ff..0a45196 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
@@ -686,7 +686,8 @@
      * Parses the manifest file, and collects data.
      * @param manifestFile The manifest file to parse.
      * @return an {@link AndroidManifestParser} or null if the parsing failed.
-     * @throws CoreException
+     * @throws CoreException for example the file does not exist in the workspace or
+     *         the workspace needs to be refreshed.
      */
     public static AndroidManifestParser parseForData(IFile manifestFile) throws CoreException {
         return parse(null /* javaProject */, manifestFile, null /* errorListener */,
@@ -698,11 +699,15 @@
      * 
      * @param osManifestFilePath The OS path of the manifest file to parse.
      * @return an {@link AndroidManifestParser} or null if the parsing failed.
-     * @throws CoreException
      */
-    public static AndroidManifestParser parseForData(String osManifestFilePath)
-            throws CoreException {
-        return parse(new File(osManifestFilePath));
+    public static AndroidManifestParser parseForData(String osManifestFilePath) {
+        try {
+            return parse(new File(osManifestFilePath));
+        } catch (CoreException e) {
+            // Ignore workspace errors (unlikely to happen since this parses an actual file,
+            // not a workspace resource).
+            return null;
+        }
     }
 
     /**
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/AbstractGraphicalLayoutEditor.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/AbstractGraphicalLayoutEditor.java
new file mode 100644
index 0000000..0499867
--- /dev/null
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/AbstractGraphicalLayoutEditor.java
@@ -0,0 +1,106 @@
+/*
+ * 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.editors.layout;
+
+import com.android.ide.eclipse.editors.layout.LayoutReloadMonitor.ILayoutReloadListener;
+import com.android.ide.eclipse.editors.layout.parts.ElementCreateCommand;
+import com.android.ide.eclipse.editors.resources.configurations.FolderConfiguration;
+import com.android.ide.eclipse.editors.uimodel.UiDocumentNode;
+import com.android.ide.eclipse.editors.uimodel.UiElementNode;
+
+import org.eclipse.gef.DefaultEditDomain;
+import org.eclipse.gef.ui.parts.GraphicalEditorWithPalette;
+import org.eclipse.gef.ui.parts.SelectionSynchronizer;
+import org.eclipse.swt.dnd.Clipboard;
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * Abstract GraphicalLayoutEditor.
+ */
+/*package*/ abstract class AbstractGraphicalLayoutEditor extends GraphicalEditorWithPalette
+    implements IWorkbenchPart, ILayoutReloadListener {
+
+    /**
+     * Sets the UI for the edition of a new file.
+     * @param configuration the configuration of the new file.
+     */
+    abstract void editNewFile(FolderConfiguration configuration);
+
+    /**
+     * Reloads this editor, by getting the new model from the {@link LayoutEditor}.
+     */
+    abstract void reloadEditor();
+
+    /**
+     * Callback for XML model changed. Only update/recompute the layout if the editor is visible
+     */
+    abstract void onXmlModelChanged();
+
+    /**
+     * Responds to a page change that made the Graphical editor page the activated page.
+     */
+    abstract void activated();
+
+    /**
+     * Responds to a page change that made the Graphical editor page the deactivated page
+     */
+    abstract void deactivated();
+
+    /**
+     * Used by LayoutEditor.UiEditorActions.selectUiNode to select a new UI Node
+     * created by  {@link ElementCreateCommand#execute()}.
+     * 
+     * @param uiNodeModel The {@link UiElementNode} to select.
+     */
+    abstract void selectModel(UiElementNode uiNodeModel);
+
+    /**
+     * Returns the selection synchronizer object.
+     * The synchronizer can be used to sync the selection of 2 or more EditPartViewers.
+     * <p/>
+     * This is changed from protected to public so that the outline can use it.
+     *
+     * @return the synchronizer
+     */
+    @Override
+    public SelectionSynchronizer getSelectionSynchronizer() {
+        return super.getSelectionSynchronizer();
+    }
+
+    /**
+     * Returns the edit domain.
+     * <p/>
+     * This is changed from protected to public so that the outline can use it.
+     *
+     * @return the edit domain
+     */
+    @Override
+    public DefaultEditDomain getEditDomain() {
+        return super.getEditDomain();
+    }
+
+    abstract void reloadPalette();
+
+    abstract void recomputeLayout();
+
+    abstract UiDocumentNode getModel();
+
+    abstract LayoutEditor getLayoutEditor();
+
+    abstract Clipboard getClipboard();
+
+}
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/GraphicalLayoutEditor.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/GraphicalLayoutEditor.java
index eb7dee6..9c529e5 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/GraphicalLayoutEditor.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/GraphicalLayoutEditor.java
@@ -86,8 +86,6 @@
 import org.eclipse.gef.editparts.ScalableFreeformRootEditPart;
 import org.eclipse.gef.palette.PaletteRoot;
 import org.eclipse.gef.requests.CreationFactory;
-import org.eclipse.gef.ui.parts.GraphicalEditorWithPalette;
-import org.eclipse.gef.ui.parts.SelectionSynchronizer;
 import org.eclipse.jface.action.Action;
 import org.eclipse.jface.action.IMenuListener;
 import org.eclipse.jface.action.IMenuManager;
@@ -141,7 +139,7 @@
  * <p/>
  * To understand Drag'n'drop: http://www.eclipse.org/articles/Article-Workbench-DND/drag_drop.html
  */
-public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
+public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor
         implements ILayoutReloadListener {
     
     private final static String THEME_SEPARATOR = "----------"; //$NON-NLS-1$
@@ -595,6 +593,7 @@
         return mPaletteRoot;
     }
 
+    @Override
     public Clipboard getClipboard() {
         return mClipboard;
     }
@@ -716,7 +715,8 @@
      * 
      * @param uiNodeModel The {@link UiElementNode} to select.
      */
-    public void selectModel(UiElementNode uiNodeModel) {
+    @Override
+    void selectModel(UiElementNode uiNodeModel) {
         GraphicalViewer viewer = getGraphicalViewer();
         
         // Give focus to the graphical viewer (in case the outline has it)
@@ -734,6 +734,7 @@
     // Local methods
     //--------------
 
+    @Override
     public LayoutEditor getLayoutEditor() {
         return mLayoutEditor;
     }
@@ -863,7 +864,8 @@
      * Sets the UI for the edition of a new file.
      * @param configuration the configuration of the new file.
      */
-    public void editNewFile(FolderConfiguration configuration) {
+    @Override
+    void editNewFile(FolderConfiguration configuration) {
         // update the configuration UI
         setConfiguration(configuration);
         
@@ -1015,6 +1017,7 @@
     /**
      * Reloads this editor, by getting the new model from the {@link LayoutEditor}.
      */
+    @Override
     void reloadEditor() {
         GraphicalViewer viewer = getGraphicalViewer();
         viewer.setContents(getModel());
@@ -1036,6 +1039,7 @@
     /**
      * Callback for XML model changed. Only update/recompute the layout if the editor is visible
      */
+    @Override
     void onXmlModelChanged() {
         if (mLayoutEditor.isGraphicalEditorActive()) {
             doXmlReload(true /* force */);
@@ -1265,10 +1269,12 @@
         mCurrentLayoutLabel.setText(current != null ? current : "(Default)");
     }
 
+    @Override
     UiDocumentNode getModel() {
         return mLayoutEditor.getUiRootNode();
     }
     
+    @Override
     void reloadPalette() {
         PaletteFactory.createPaletteRoot(mPaletteRoot, mLayoutEditor.getTargetData());
     }
@@ -1667,6 +1673,7 @@
     /**
      * Recomputes the layout with the help of layoutlib.
      */
+    @Override
     @SuppressWarnings("deprecation")
     void recomputeLayout() {
         doXmlReload(false /* force */);
@@ -1968,6 +1975,7 @@
     /**
      * Responds to a page change that made the Graphical editor page the activated page.
      */
+    @Override
     void activated() {
         if (mNeedsRecompute || mNeedsXmlReload) {
             recomputeLayout();
@@ -1977,6 +1985,7 @@
     /**
      * Responds to a page change that made the Graphical editor page the deactivated page
      */
+    @Override
     void deactivated() {
         // nothing to be done here for now.
     }
@@ -2234,31 +2243,6 @@
     }
 
     /**
-     * Returns the selection synchronizer object.
-     * The synchronizer can be used to sync the selection of 2 or more EditPartViewers.
-     * <p/>
-     * This is changed from protected to public so that the outline can use it.
-     *
-     * @return the synchronizer
-     */
-    @Override
-    public SelectionSynchronizer getSelectionSynchronizer() {
-        return super.getSelectionSynchronizer();
-    }
-
-    /**
-     * Returns the edit domain.
-     * <p/>
-     * This is changed from protected to public so that the outline can use it.
-     *
-     * @return the edit domain
-     */
-    @Override
-    public DefaultEditDomain getEditDomain() {
-        return super.getEditDomain();
-    }
-
-    /**
      * Creates a new layout file from the specificed {@link FolderConfiguration}.
      */
     private void createAlternateLayout(final FolderConfiguration config) {
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutEditor.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutEditor.java
index dabe797..f3a5113 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutEditor.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutEditor.java
@@ -55,7 +55,7 @@
     /** Root node of the UI element hierarchy */
     private UiDocumentNode mUiRootNode;
     
-    private GraphicalLayoutEditor mGraphicalEditor;
+    private AbstractGraphicalLayoutEditor mGraphicalEditor;
     private int mGraphicalEditorIndex;
     /** Implementation of the {@link IContentOutlinePage} for this editor */
     private UiContentOutlinePage mOutline;
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/UiContentOutlinePage.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/UiContentOutlinePage.java
index 3e0f5d8..536e902 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/UiContentOutlinePage.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/UiContentOutlinePage.java
@@ -70,7 +70,7 @@
  */
 class UiContentOutlinePage extends ContentOutlinePage {
 
-    private GraphicalLayoutEditor mEditor;
+    private AbstractGraphicalLayoutEditor mEditor;
     
     private Action mAddAction;
     private Action mDeleteAction;
@@ -79,7 +79,7 @@
     
     private UiOutlineActions mUiActions = new UiOutlineActions();
 
-    public UiContentOutlinePage(GraphicalLayoutEditor editor, final EditPartViewer viewer) {
+    public UiContentOutlinePage(AbstractGraphicalLayoutEditor editor, final EditPartViewer viewer) {
         super(viewer);
         mEditor = editor;
         IconFactory factory = IconFactory.getInstance();
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/descriptors/LayoutDescriptors.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/descriptors/LayoutDescriptors.java
index c3f4dd8..5726d78 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/descriptors/LayoutDescriptors.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/descriptors/LayoutDescriptors.java
@@ -18,7 +18,6 @@
 
 import com.android.ide.eclipse.common.AndroidConstants;
 import com.android.ide.eclipse.common.resources.DeclareStyleableInfo;
-import com.android.ide.eclipse.common.resources.ResourceType;
 import com.android.ide.eclipse.common.resources.ViewClassInfo;
 import com.android.ide.eclipse.common.resources.DeclareStyleableInfo.AttributeInfo;
 import com.android.ide.eclipse.common.resources.ViewClassInfo.LayoutParamsInfo;
@@ -27,7 +26,6 @@
 import com.android.ide.eclipse.editors.descriptors.DocumentDescriptor;
 import com.android.ide.eclipse.editors.descriptors.ElementDescriptor;
 import com.android.ide.eclipse.editors.descriptors.IDescriptorProvider;
-import com.android.ide.eclipse.editors.descriptors.ReferenceAttributeDescriptor;
 import com.android.ide.eclipse.editors.descriptors.SeparatorAttributeDescriptor;
 import com.android.sdklib.SdkConstants;
 
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/CompiledResourcesMonitor.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/CompiledResourcesMonitor.java
index fa09305..2d14c06 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/CompiledResourcesMonitor.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/CompiledResourcesMonitor.java
@@ -217,8 +217,10 @@
         try {
             IFile manifestFile = AndroidManifestParser.getManifest(project);
             AndroidManifestParser data = AndroidManifestParser.parseForData(manifestFile);
-            String javaPackage = data.getPackage();
-            return javaPackage + ".R"; //$NON-NLS-1$
+            if (data != null) {
+                String javaPackage = data.getPackage();
+                return javaPackage + ".R"; //$NON-NLS-1$
+            }
         } catch (CoreException e) {
             // This will typically happen either because the manifest file is not present
             // and/or the workspace needs to be refreshed.
@@ -227,8 +229,8 @@
                     "Failed to find the package of the AndroidManifest of project %1$s. Reason: %2$s",
                     project.getName(),
                     e.getMessage());
-            return null;
         }
+        return null;
     }
     
 }
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiResourceAttributeNode.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiResourceAttributeNode.java
index 48f8a7f..32cac9f 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiResourceAttributeNode.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiResourceAttributeNode.java
@@ -158,6 +158,35 @@
         return null;
     }
     
+    /**
+     * Gets all the values one could use to auto-complete a "resource" value in an XML
+     * content assist.
+     * <p/>
+     * Typically the user is editing the value of an attribute in a resource XML, e.g.
+     *   <pre> "&lt;Button android:test="@string/my_[caret]_string..." </pre>
+     * <p/>
+     * 
+     * "prefix" is the value that the user has typed so far (or more exactly whatever is on the
+     * left side of the insertion point). In the example above it would be "@style/my_".
+     * <p/>
+     * 
+     * To avoid a huge long list of values, the completion works on two levels:
+     * <ul>
+     * <li> If a resource type as been typed so far (e.g. "@style/"), then limit the values to
+     *      the possible completions that match this type.
+     * <li> If no resource type as been typed so far, then return the various types that could be
+     *      completed. So if the project has only strings and layouts resources, for example,
+     *      the returned list will only include "@string/" and "@layout/".
+     * </ul>
+     * 
+     * Finally if anywhere in the string we find the special token "android:", we use the
+     * current framework system resources rather than the project resources.
+     * This works for both "@android:style/foo" and "@style/android:foo" conventions even though
+     * the reconstructed name will always be of the former form.
+     * 
+     * Note that "android:" here is a keyword specific to Android resources and should not be
+     * mixed with an XML namespace for an XML attribute name. 
+     */
     @Override
     public String[] getPossibleValues(String prefix) {
         IResourceRepository repository = null;
@@ -174,6 +203,8 @@
             }
         } else {
             // If there's a prefix with "android:" in it, use the system resources
+            //
+            // TODO find a way to only list *public* framework resources here.
             AndroidTargetData data = editor.getTargetData();
             repository = data.getSystemResources();
             isSystem = true;