summaryrefslogtreecommitdiff
path: root/src/plugins/launch/src/com/motorola/studio
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/launch/src/com/motorola/studio')
-rw-r--r--src/plugins/launch/src/com/motorola/studio/android/launch/ILaunchConfigurationConstants.java151
-rw-r--r--src/plugins/launch/src/com/motorola/studio/android/launch/LaunchConfigurationShortcut.java408
-rw-r--r--src/plugins/launch/src/com/motorola/studio/android/launch/LaunchPlugin.java78
-rw-r--r--src/plugins/launch/src/com/motorola/studio/android/launch/LaunchUtils.java515
-rw-r--r--src/plugins/launch/src/com/motorola/studio/android/launch/StudioAndroidConfigurationDelegate.java762
-rw-r--r--src/plugins/launch/src/com/motorola/studio/android/launch/i18n/LaunchNLS.java130
-rw-r--r--src/plugins/launch/src/com/motorola/studio/android/launch/i18n/launchNLS.properties57
-rw-r--r--src/plugins/launch/src/com/motorola/studio/android/launch/ui/AndroidProjectsSelectionDialog.java104
-rw-r--r--src/plugins/launch/src/com/motorola/studio/android/launch/ui/DeviceSelectionDialog.java136
-rw-r--r--src/plugins/launch/src/com/motorola/studio/android/launch/ui/LaunchConfigurationTab.java981
-rw-r--r--src/plugins/launch/src/com/motorola/studio/android/launch/ui/LaunchConfigurationTabGroup.java55
-rw-r--r--src/plugins/launch/src/com/motorola/studio/android/launch/ui/StartedInstancesDialog.java386
12 files changed, 3763 insertions, 0 deletions
diff --git a/src/plugins/launch/src/com/motorola/studio/android/launch/ILaunchConfigurationConstants.java b/src/plugins/launch/src/com/motorola/studio/android/launch/ILaunchConfigurationConstants.java
new file mode 100644
index 0000000..58bbdbf
--- /dev/null
+++ b/src/plugins/launch/src/com/motorola/studio/android/launch/ILaunchConfigurationConstants.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.motorola.studio.android.launch;
+
+import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
+
+import com.android.ide.eclipse.adt.internal.launch.AndroidLaunchConfiguration.TargetMode;
+import com.android.ide.eclipse.adt.internal.launch.LaunchConfigDelegate;
+
+/**
+ * This interface holds the constants for Launch Configuration
+ */
+@SuppressWarnings("restriction")
+public interface ILaunchConfigurationConstants
+{
+
+ /**
+ * Launch configuration id
+ */
+ public final static String LAUNCH_CONFIGURATION_TYPE_EXTENSION_ID =
+ "androidLaunchConfigurationType";
+
+ public final static String MOTODEV_APP_ICO = "icons/motodevapp.gif";
+
+ public final static String DEFAULT_VALUE = "";
+
+ public final static boolean DEFAULT_BOOL_VALUE = false;
+
+ /**
+ * Launch Configuration attribute ID: Project Name
+ */
+ public final static String ATTR_PROJECT_NAME =
+ IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME;
+
+ /**
+ * Launch Configuration attribute ID : Terminate Boolean If true, the VM
+ * supports terminate action.
+ */
+ public final static String ATTR_ALLOW_TERMINATE =
+ IJavaLaunchConfigurationConstants.ATTR_ALLOW_TERMINATE;
+
+ public final static boolean ATTR_ALLOW_TERMINATE_DEFAULT = true;
+
+ /**
+ * Launch Configuration attribute ID : Launch Action. The type of launch to
+ * be performed.
+ * 0: launch default activity.
+ * 1: launch specified activity.
+ * 2: Do Nothing
+ *
+ * Should always be 'activity' for now.
+ */
+ public final static String ATTR_LAUNCH_ACTION = LaunchConfigDelegate.ATTR_LAUNCH_ACTION;
+
+ public final static int ATTR_LAUNCH_ACTION_DEFAULT = LaunchConfigDelegate.ACTION_DEFAULT;
+
+ public final static int ATTR_LAUNCH_ACTION_DO_NOTHING = LaunchConfigDelegate.ACTION_DO_NOTHING;
+
+ public final static int ATTR_LAUNCH_ACTION_ACTIVITY = LaunchConfigDelegate.ACTION_ACTIVITY;
+
+ /**
+ * Launch Configuration attribute ID: Activity Name
+ */
+ public final static String ATTR_ACTIVITY = LaunchConfigDelegate.ATTR_ACTIVITY;
+
+ /**
+ * Launch Configuration attribute ID: Target Mode
+ * True: Automatic
+ * False: Manual
+ */
+ public final static String ATTR_TARGET_MODE = LaunchConfigDelegate.ATTR_TARGET_MODE;
+
+ public final static TargetMode ATTR_TARGET_MODE_DEFAULT =
+ LaunchConfigDelegate.DEFAULT_TARGET_MODE;
+
+ /**
+ * This is the attribute we use to store the name of the device. We could use ADT's directly if we were
+ * not forced to remove ADT's entry for it to work with handsets. If we don't store in our own key, the
+ * device name not to be restored the next time the user opens the Run As window, which is against
+ * Eclipse standards.
+ */
+ public final static String ATTR_DEVICE_INSTANCE_NAME =
+ "com.motorola.studio.android.launch.instanceName";
+
+ /**
+ * Launch Configuration attribute ID: Instance Name (VM Name for ADT)
+ */
+ public final static String ATTR_ADT_DEVICE_INSTANCE_NAME = LaunchConfigDelegate.ATTR_AVD_NAME;
+
+ /**
+ * Launch Configuration attribute ID: Emulator Network Speed
+ *
+ * Default value is 0.
+ */
+ public final static String ATTR_SPEED = LaunchConfigDelegate.ATTR_SPEED;
+
+ public final static int ATTR_SPEED_DEFAULT = LaunchConfigDelegate.DEFAULT_SPEED;
+
+ /**
+ * Launch Configuration attribute ID: Emulator Network Latency
+ */
+ public final static String ATTR_DELAY = LaunchConfigDelegate.ATTR_DELAY;
+
+ public final static int ATTR_DELAY_DEFAULT = LaunchConfigDelegate.DEFAULT_DELAY;
+
+ /**
+ * Launch Configuration attribute ID: Wipe Data
+ *
+ * Default value is FALSE.
+ *
+ */
+ public final static String ATTR_WIPE_DATA = LaunchConfigDelegate.ATTR_WIPE_DATA;
+
+ public final static boolean ATTR_WIPE_DATA_DEFAULT = LaunchConfigDelegate.DEFAULT_WIPE_DATA;
+
+ /**
+ * Launch Configuration attribute ID: Boot Animation
+ *
+ * Default value is FALSE.
+ */
+ public final static String ATTR_NO_BOOT_ANIM = LaunchConfigDelegate.ATTR_NO_BOOT_ANIM;
+
+ public final static boolean ATTR_NO_BOOT_ANIM_DEFAULT =
+ LaunchConfigDelegate.DEFAULT_NO_BOOT_ANIM;
+
+ /**
+ * Launch Configuration attribute ID: Command Line
+ *
+ * Additional command line options. Default value is empty.
+ */
+ public final static String ATTR_COMMANDLINE = LaunchConfigDelegate.ATTR_COMMANDLINE;
+
+ /*
+ * Console View ID
+ */
+ public final static String ANDROID_CONSOLE_ID = "Android";
+}
diff --git a/src/plugins/launch/src/com/motorola/studio/android/launch/LaunchConfigurationShortcut.java b/src/plugins/launch/src/com/motorola/studio/android/launch/LaunchConfigurationShortcut.java
new file mode 100644
index 0000000..b849a0f
--- /dev/null
+++ b/src/plugins/launch/src/com/motorola/studio/android/launch/LaunchConfigurationShortcut.java
@@ -0,0 +1,408 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.motorola.studio.android.launch;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationType;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.debug.ui.ILaunchShortcut;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IEditorPart;
+
+import com.motorola.studio.android.adt.ISerialNumbered;
+import com.motorola.studio.android.adt.SdkUtils;
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.devices.DevicesManager;
+import com.motorola.studio.android.launch.i18n.LaunchNLS;
+
+public class LaunchConfigurationShortcut implements ILaunchShortcut
+{
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.ILaunchShortcut#launch(org.eclipse.jface.viewers.ISelection, java.lang.String)
+ */
+ public void launch(ISelection selection, String mode)
+ {
+ ILaunchConfiguration launchConfiguration =
+ getLaunchConfigurationForSelection(selection, true);
+ handleLaunch(mode, launchConfiguration);
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.ILaunchShortcut#launch(org.eclipse.ui.IEditorPart, java.lang.String)
+ */
+ public void launch(IEditorPart editor, String mode)
+ {
+ IResource resource = (IResource) editor.getEditorInput().getAdapter(IResource.class);
+ if (resource != null)
+ {
+ ILaunchConfiguration launchConfiguration =
+ getLaunchConfigurationForResource(resource, true);
+ handleLaunch(mode, launchConfiguration);
+ }
+ }
+
+ private void handleLaunch(String mode, ILaunchConfiguration launchConfiguration)
+ {
+ if (launchConfiguration != null)
+ {
+ final ILaunchConfiguration config = launchConfiguration;
+ final String launchMode = mode;
+
+ Job job = new Job("Launch Job")
+ {
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor)
+ {
+ IStatus status = Status.OK_STATUS;
+ try
+ {
+ config.launch(launchMode, monitor);
+ }
+ catch (CoreException e)
+ {
+ status =
+ new Status(
+ IStatus.ERROR,
+ LaunchPlugin.PLUGIN_ID,
+ LaunchNLS.ERR_LaunchConfigurationShortcut_CannotLaunchSelectedResourceMsg,
+ e);
+ }
+ return status;
+ }
+ };
+
+ job.schedule();
+ }
+ else
+ {
+ LaunchUtils.showErrorDialog(LaunchNLS.ERR_LaunchConfigurationShortcut_MsgTitle,
+ LaunchNLS.ERR_LaunchConfigurationShortcut_CannotLaunchSelectedResourceMsg);
+ }
+ }
+
+ /**
+ * Gets a launch configuration for a desired selection
+ *
+ * @param selection The selection
+ * @param create If the launch configuration does not exist, does it must be created?
+ *
+ * @return The launch configuration for the selection
+ */
+
+ private ILaunchConfiguration getLaunchConfigurationForSelection(ISelection selection,
+ boolean create)
+ {
+ ILaunchConfiguration config = null;
+ IStructuredSelection newSelection;
+ Object selectedObject;
+ IResource selectedResource = null;
+
+ if (selection instanceof IStructuredSelection)
+ {
+ newSelection = (IStructuredSelection) selection;
+ selectedObject = newSelection.getFirstElement();
+
+ if (selectedObject instanceof IResource)
+ {
+ selectedResource = (IResource) selectedObject;
+ }
+ else if (selectedObject instanceof IJavaElement)
+ {
+ selectedResource = ((IJavaElement) selectedObject).getResource();
+ }
+
+ if (selectedResource != null)
+ {
+ config = getLaunchConfigurationForResource(selectedResource, create);
+ }
+ }
+
+ return config;
+ }
+
+ /**
+ * Gets a launch configuration for a resource
+ *
+ * @param resource The resource
+ * @param create If the launch configuration does not exist, does it must be created?
+ *
+ * @return The launch configuration for the resource
+ */
+ private ILaunchConfiguration getLaunchConfigurationForResource(IResource resource,
+ boolean create)
+ {
+ IResource app;
+ IResource project;
+ ILaunchConfiguration config = null;
+
+ if (resource != null)
+ {
+ if (resource.getType() == IResource.PROJECT)
+ {
+ project = resource;
+ }
+ else
+ {
+ project = resource.getProject();
+ }
+ // Try to retrieve an existent launch configuration
+ config = findLaunchConfiguration(project);
+
+ if ((config == null) && create)
+ {
+ // No launch configuration could be found. Try to create a
+ // launch configuration with the first runnable activity
+ app = getFirstActivity((IProject) project);
+
+ // If no application could be found, use the project
+ // to create the launch configuration
+ app = app == null ? resource : app;
+ config = createLaunchConfiguration(app);
+ }
+
+ }
+
+ return config;
+ }
+
+ /**
+ * Finds a launch configuration for a descriptor, a mpkg file or a project
+ *
+ * @param resource A descriptor, a mpkg file or a project
+ *
+ * @return A launch configuration or null if it could not be found
+ */
+ private ILaunchConfiguration findLaunchConfiguration(IResource resource)
+ {
+ ILaunchConfiguration launchConfig = null;
+
+ if (resource != null)
+ {
+ try
+ {
+ List<ILaunchConfiguration> projectLC =
+ getProjectLaunchConfigurations(resource.getProject());
+
+ if ((resource.getType() == IResource.PROJECT)
+ || (resource.getType() == IResource.FILE))
+ {
+ // If the resource is a project, return the first launch configuration found
+ // for the project
+ if (!projectLC.isEmpty())
+ {
+ launchConfig = projectLC.iterator().next();
+ }
+ }
+ }
+ catch (CoreException e)
+ {
+ StudioLogger.error(
+ LaunchConfigurationShortcut.class,
+ "Error searching for launch configuration for resource: "
+ + resource.getName(), e);
+ }
+ }
+
+ return launchConfig;
+ }
+
+ /**
+ * Scan for all LaunchConfigurations associated with a project.
+ * @param selectedResource, the project itself or any file within the project to be scanned
+ * @return List with all LaunchConfiguration associated with a project or an empty List if none is found.
+ * @throws CoreException
+ */
+ protected List<ILaunchConfiguration> getProjectLaunchConfigurations(IProject project)
+ throws CoreException
+ {
+ List<ILaunchConfiguration> matches;
+
+ ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager();
+ ILaunchConfigurationType motodevLaunchType =
+ launchManager
+ .getLaunchConfigurationType(ILaunchConfigurationConstants.LAUNCH_CONFIGURATION_TYPE_EXTENSION_ID);
+
+ ILaunchConfiguration[] motodevLaunchConfigurations =
+ launchManager.getLaunchConfigurations(motodevLaunchType);
+ matches = new ArrayList<ILaunchConfiguration>(motodevLaunchConfigurations.length);
+ for (ILaunchConfiguration launchConfiguration : motodevLaunchConfigurations)
+ {
+ if (launchConfiguration.getAttribute(ILaunchConfigurationConstants.ATTR_PROJECT_NAME,
+ "").equals(project.getName())) //$NON-NLS-1$
+ {
+ matches.add(launchConfiguration);
+ }
+ }
+
+ return matches;
+ }
+
+ /**
+ * Gets the first runnable application/widget for a project. It can be a
+ * application/widget root folder or a mpkg file
+ *
+ * @param project The project
+ *
+ * @return The first runnable application/widget or null if it does not exist
+ */
+ private IResource getFirstActivity(IProject project)
+ {
+ IResource app = null;
+
+ String[] allActivities = LaunchUtils.getProjectActivities(project);
+
+ if ((allActivities != null) && (allActivities.length >= 1))
+ {
+ app = project.getFile(allActivities[0]);
+ }
+
+ return app;
+ }
+
+ /**
+ * Creates a launch configuration based on a resource
+ *
+ * @param resource The resource
+ *
+ * @return A launch configuration
+ */
+ private ILaunchConfiguration createLaunchConfiguration(IResource resource)
+ {
+ ILaunchConfiguration config = null;
+ ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager();
+ ILaunchConfigurationType motodevLaunchType =
+ launchManager
+ .getLaunchConfigurationType(ILaunchConfigurationConstants.LAUNCH_CONFIGURATION_TYPE_EXTENSION_ID);
+ String projectName;
+
+ String configBaseName = resource.getName();
+
+ String launchConfigurationName =
+ launchManager.generateLaunchConfigurationName(configBaseName);
+ try
+ {
+ ILaunchConfigurationWorkingCopy workingCopy =
+ motodevLaunchType.newInstance(null, launchConfigurationName);
+
+ //Set Defaults
+ workingCopy.setAttribute(ILaunchConfigurationConstants.ATTR_PROJECT_NAME,
+ ILaunchConfigurationConstants.DEFAULT_VALUE);
+ workingCopy.setAttribute(ILaunchConfigurationConstants.ATTR_ACTIVITY,
+ ILaunchConfigurationConstants.DEFAULT_VALUE);
+ // It is default not to exist Preferred AVD attribute, so we just set the Studio's
+ // device instance name attribute here
+ workingCopy.setAttribute(ILaunchConfigurationConstants.ATTR_DEVICE_INSTANCE_NAME,
+ (String) null);
+ LaunchUtils.setADTLaunchConfigurationDefaults(workingCopy);
+
+ //Launch Settings
+ IProject project = resource.getProject();
+ projectName = project.getName();
+ workingCopy.setAttribute(ILaunchConfigurationConstants.ATTR_PROJECT_NAME, projectName);
+
+ if (resource.getType() != IResource.PROJECT)
+ {
+ workingCopy.setAttribute(ILaunchConfigurationConstants.ATTR_ACTIVITY,
+ resource.getName());
+ }
+
+ String deviceName = getSelectedInstanceName(project);
+ workingCopy.setAttribute(ILaunchConfigurationConstants.ATTR_DEVICE_INSTANCE_NAME,
+ deviceName);
+ // Preferred AVD name shall only exist in the launch configuration if an AVD is selected
+ Collection<String> validAvds = SdkUtils.getAllValidVmNames();
+ if (validAvds.contains(deviceName))
+ {
+ workingCopy.setAttribute(
+ ILaunchConfigurationConstants.ATTR_ADT_DEVICE_INSTANCE_NAME, deviceName);
+ }
+
+ if (workingCopy.getAttribute(ILaunchConfigurationConstants.ATTR_ACTIVITY,
+ ILaunchConfigurationConstants.DEFAULT_VALUE).equals(""))
+ {
+ workingCopy.setAttribute(ILaunchConfigurationConstants.ATTR_LAUNCH_ACTION,
+ ILaunchConfigurationConstants.ATTR_LAUNCH_ACTION_DEFAULT);
+ }
+
+ config = workingCopy.doSave();
+ }
+ catch (CoreException e)
+ {
+ StudioLogger.error(LaunchConfigurationShortcut.class,
+ "Error creating launch configuration for resource: " + resource.getName(), e);
+ }
+
+ return config;
+ }
+
+ /**
+ * Get a available and compatible instance name.
+ * This method seeks within all registered instances, following the criteria:
+ * Phone device with "full" compatibility (API version = project min. API)
+ * Phone device with "partial" compatibility (API version > project min. API)
+ * Emulator device with "full" compatibility (API version = project min. API)
+ * Emulator device with "partial" compatibility (API version = project min. API)
+ * @param project
+ */
+ protected String getSelectedInstanceName(IProject project)
+ {
+ String selectedDevice = "";
+
+ //get all instances according ddms
+ Collection<ISerialNumbered> instances = DevicesManager.getInstance().getAllDevicesSorted();
+ String candidate = "";
+ for (ISerialNumbered instance : instances)
+ {
+
+ IStatus compatible = LaunchUtils.isCompatible(project, instance);
+ if (compatible.isOK())
+ {
+ selectedDevice = instance.getDeviceName();
+ break;
+ }
+ else if (compatible.getSeverity() == IStatus.WARNING)
+ {
+ candidate = instance.getDeviceName();
+ }
+
+ }
+ if ((selectedDevice.equals("")) && !candidate.equals(""))
+ {
+ selectedDevice = candidate;
+ }
+
+ return selectedDevice;
+ }
+
+}
diff --git a/src/plugins/launch/src/com/motorola/studio/android/launch/LaunchPlugin.java b/src/plugins/launch/src/com/motorola/studio/android/launch/LaunchPlugin.java
new file mode 100644
index 0000000..106a460
--- /dev/null
+++ b/src/plugins/launch/src/com/motorola/studio/android/launch/LaunchPlugin.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.motorola.studio.android.launch;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class LaunchPlugin extends AbstractUIPlugin
+{
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "com.motorola.studio.android.launch";
+
+ // The shared instance
+ private static LaunchPlugin plugin;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext
+ * )
+ */
+ @Override
+ public void start(BundleContext context) throws Exception
+ {
+ StudioLogger.debug(LaunchPlugin.class, "Starting MOTODEV Android Launch Plugin...");
+
+ super.start(context);
+ plugin = this;
+
+ StudioLogger.debug(LaunchPlugin.class, "MOTODEV Android Launch Plugin started.");
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext
+ * )
+ */
+ @Override
+ public void stop(BundleContext context) throws Exception
+ {
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static LaunchPlugin getDefault()
+ {
+ return plugin;
+ }
+
+}
diff --git a/src/plugins/launch/src/com/motorola/studio/android/launch/LaunchUtils.java b/src/plugins/launch/src/com/motorola/studio/android/launch/LaunchUtils.java
new file mode 100644
index 0000000..10b7d27
--- /dev/null
+++ b/src/plugins/launch/src/com/motorola/studio/android/launch/LaunchUtils.java
@@ -0,0 +1,515 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.motorola.studio.android.launch;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.sequoyah.device.framework.factory.InstanceRegistry;
+import org.eclipse.sequoyah.device.framework.model.IInstance;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+import com.android.ide.eclipse.adt.io.IFolderWrapper;
+import com.android.sdklib.xml.AndroidManifestParser;
+import com.android.sdklib.xml.ManifestData;
+import com.android.sdklib.xml.ManifestData.Activity;
+import com.motorola.studio.android.AndroidPlugin;
+import com.motorola.studio.android.adt.DDMSFacade;
+import com.motorola.studio.android.adt.ISerialNumbered;
+import com.motorola.studio.android.adt.SdkUtils;
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.emulator.core.devfrm.DeviceFrameworkManager;
+import com.motorola.studio.android.emulator.core.model.IAndroidEmulatorInstance;
+import com.motorola.studio.android.emulator.logic.IAndroidLogicInstance;
+import com.motorola.studio.android.launch.i18n.LaunchNLS;
+
+/**
+ * DESCRIPTION: Utilities for Studio for Android Launch use
+ *
+ * RESPONSIBILITY: Provide common utility methods that can be used by any Studio
+ * for Android Launch plugin.
+ *
+ * COLABORATORS: None
+ *
+ * USAGE: This class should not be instantiated and its methods should be called
+ * statically.
+ */
+@SuppressWarnings("restriction")
+public class LaunchUtils
+{
+ /**
+ * Retrieve a instance by name
+ *
+ * @param instanceName
+ * @return IInstance with the given name or null if none is found, or it's not available.
+ */
+ public static String getSerialNumberForInstance(String instanceName)
+ {
+ String serial = null;
+ List<IInstance> list = InstanceRegistry.getInstance().getInstances();
+ for (IInstance inst : list)
+ {
+ if ((inst.getName().equals(instanceName)) && (inst instanceof ISerialNumbered))
+ {
+ serial = ((ISerialNumbered) inst).getSerialNumber();
+ }
+ }
+ return serial;
+ }
+
+ /**
+ * Get a project in the current workspace based on its projectName
+ *
+ * @param projectName
+ * @return the IProject representing the project, or null if none is found
+ */
+ public static IProject getProject(String projectName)
+ {
+ IProject project = null;
+
+ Path projectPath = new Path(projectName);
+ if (projectPath.isValidSegment(projectName))
+ {
+ project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
+ }
+
+ return project;
+ }
+
+ /**
+ * Verify if a given project is supported by the Studio for Android
+ * Launcher, checking if the project is a Android project
+ *
+ * @param project
+ * to be verified
+ * @return true if project is a an Android project, false otherwise.
+ */
+ public static boolean isProjectSupported(IProject project)
+ {
+ boolean hasNature = false;
+ boolean isLibrary = true;
+
+ if ((project != null) && project.isOpen())
+ {
+ try
+ {
+ hasNature = project.hasNature(AndroidPlugin.Android_Nature);
+ isLibrary = SdkUtils.isLibraryProject(project);
+ }
+ catch (CoreException e)
+ {
+ // Do nothing
+ }
+ }
+
+ return hasNature && !isLibrary;
+ }
+
+ /**
+ * Get all Android Projects within the current workspace.
+ *
+ * @return IProject array with all Android projects in the current
+ * workspace, or an empty array if none is found
+ */
+ public static IProject[] getSupportedProjects()
+ {
+ Collection<IProject> projectCollection = new ArrayList<IProject>();
+ IProject[] projectsName = ResourcesPlugin.getWorkspace().getRoot().getProjects();
+
+ /* select only Android projects */
+ for (IProject project : projectsName)
+ {
+ if (project.isAccessible())
+ {
+ if (LaunchUtils.isProjectSupported(project))
+ {
+ projectCollection.add(project);
+ }
+ }
+ }
+
+ return projectCollection.toArray(new IProject[projectCollection.size()]);
+ }
+
+ /**
+ * Retrieve the project activities from the MANIFEST.xml file
+ *
+ * @param project
+ * @return An array of activities.
+ */
+ public static String[] getProjectActivities(IProject project)
+ {
+
+ String[] activities = null;
+ Activity[] adtActivities = null;
+
+ // parse the manifest for the list of activities.
+ try
+ {
+ ManifestData manifestParser = AndroidManifestParser.parse(new IFolderWrapper(project));
+
+ if (manifestParser != null)
+ {
+ adtActivities = manifestParser.getActivities();
+ }
+
+ if ((adtActivities != null) && (adtActivities.length > 0))
+ {
+ activities = new String[adtActivities.length];
+ for (int i = 0; i < adtActivities.length; i++)
+ {
+ activities[i] = adtActivities[i].getName();
+ }
+ }
+
+ }
+ catch (Exception e)
+ {
+ StudioLogger.error(LaunchUtils.class,
+ "An error occurred trying to parse AndroidManifest", e);
+ }
+
+ return activities;
+
+ }
+
+ /**
+ * Set the default launch configuration values
+ */
+ public static void setADTLaunchConfigurationDefaults(
+ ILaunchConfigurationWorkingCopy configuration)
+ {
+ configuration.setAttribute(ILaunchConfigurationConstants.ATTR_ALLOW_TERMINATE,
+ ILaunchConfigurationConstants.ATTR_ALLOW_TERMINATE_DEFAULT);
+ configuration.setAttribute(ILaunchConfigurationConstants.ATTR_LAUNCH_ACTION,
+ ILaunchConfigurationConstants.ATTR_LAUNCH_ACTION_DEFAULT);
+ configuration.setAttribute(ILaunchConfigurationConstants.ATTR_TARGET_MODE,
+ ILaunchConfigurationConstants.ATTR_TARGET_MODE_DEFAULT.toString());
+ configuration.setAttribute(ILaunchConfigurationConstants.ATTR_SPEED,
+ ILaunchConfigurationConstants.ATTR_SPEED_DEFAULT);
+ configuration.setAttribute(ILaunchConfigurationConstants.ATTR_DELAY,
+ ILaunchConfigurationConstants.ATTR_DELAY_DEFAULT);
+ configuration.setAttribute(ILaunchConfigurationConstants.ATTR_WIPE_DATA,
+ ILaunchConfigurationConstants.ATTR_WIPE_DATA_DEFAULT);
+ configuration.setAttribute(ILaunchConfigurationConstants.ATTR_NO_BOOT_ANIM,
+ ILaunchConfigurationConstants.ATTR_NO_BOOT_ANIM_DEFAULT);
+ configuration.setAttribute(ILaunchConfigurationConstants.ATTR_COMMANDLINE,
+ ILaunchConfigurationConstants.DEFAULT_VALUE);
+
+ }
+
+ /**
+ * Update the launch configuration values
+ */
+ public static void updateLaunchConfigurationDefaults(
+ ILaunchConfigurationWorkingCopy configuration)
+ {
+ try
+ {
+ String deviceName =
+ configuration.getAttribute(
+ ILaunchConfigurationConstants.ATTR_DEVICE_INSTANCE_NAME, "");
+
+ if ((deviceName != null) && !deviceName.equals(""))
+ {
+ IAndroidEmulatorInstance deviceInstance =
+ DeviceFrameworkManager.getInstance().getInstanceByName(deviceName);
+
+ if (deviceInstance instanceof IAndroidLogicInstance)
+ {
+ String commandLine =
+ ((IAndroidLogicInstance) deviceInstance).getCommandLineArguments();
+ configuration.setAttribute(ILaunchConfigurationConstants.ATTR_COMMANDLINE,
+ commandLine);
+ }
+ }
+ }
+ catch (CoreException e)
+ {
+ StudioLogger.error(LaunchUtils.class,
+ "Error updating launch configuration values for : " + configuration.getName(),
+ e);
+ }
+ }
+
+ /**
+ * Get the shell of the active workbench or null if there is no active
+ * workbench.
+ *
+ * @return the active workbench shell
+ */
+ public static Shell getActiveWorkbenchShell()
+ {
+ class ActiveShellRunnable implements Runnable
+ {
+ private Shell shell = null;
+
+ public Shell getShell()
+ {
+ return shell;
+ }
+
+ public void run()
+ {
+ IWorkbenchWindow activeWorkbench =
+ PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+
+ if (activeWorkbench != null)
+ {
+ shell = activeWorkbench.getShell();
+ }
+ }
+ }
+ ;
+
+ ActiveShellRunnable runnable = new ActiveShellRunnable();
+ PlatformUI.getWorkbench().getDisplay().syncExec(runnable);
+
+ return runnable.getShell();
+ }
+
+ /**
+ * Show the error message using the given title and message
+ *
+ * @param title
+ * of the error dialog
+ * @param message
+ * to be displayed in the error dialog.
+ */
+ public static void showErrorDialog(final String title, final String message)
+ {
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable()
+ {
+ public void run()
+ {
+ IWorkbenchWindow ww = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ MessageDialog.openError(ww.getShell(), title, message);
+ }
+ });
+ }
+
+ public static ISerialNumbered resolveInstance(List<IInstance> instances)
+ {
+ ISerialNumbered theInstance = null;
+ Iterator<IInstance> it = instances.iterator();
+ while (it.hasNext() && (theInstance == null))
+ {
+ IInstance anInstance = it.next();
+ if (anInstance instanceof ISerialNumbered)
+ {
+ theInstance = (ISerialNumbered) anInstance;
+ }
+ }
+ return theInstance;
+ }
+
+ /**
+ * Check if an instanceName is compatible with some project
+ * @param project
+ * @param instanceName
+ * @return {@link IStatus#OK} if fully compatible, {@link IStatus#WARNING} if can be compatible and {@link IStatus#ERROR} if not compatible. Return <code>null</code> if the instance does not exists
+ */
+
+ public static IStatus isCompatible(IProject project, String instanceName)
+ {
+ IStatus status = null;
+ List<IInstance> instances = InstanceRegistry.getInstance().getInstances();
+ for (IInstance instance : instances)
+ {
+ if (instanceName.equals(instance.getName()))
+ {
+ if (instance instanceof ISerialNumbered)
+ {
+ status = isCompatible(project, (ISerialNumbered) instance);
+ break;
+ }
+ }
+ }
+ return status;
+ }
+
+ /**
+ * Check if the given instance name is compatible with the given project
+ * @param project
+ * @param instance
+ * @return {@link IStatus#OK} if fully compatible, {@link IStatus#WARNING} if can be compatible and {@link IStatus#ERROR} if not compatible. Return <code>null</code> if the instance does not exists
+ */
+ public static IStatus isCompatible(IProject project, ISerialNumbered instance)
+ {
+ IStatus compatible = null;
+ int projectAPILevel = SdkUtils.getApiVersionNumberForProject(project);
+ String minSdkVersionStr = SdkUtils.getMinSdkVersion(project);
+ int minSdkVersion;
+ boolean isProjectTargetAPlatform =
+ SdkUtils.getTarget(project) != null ? SdkUtils.getTarget(project).isPlatform()
+ : true;
+
+ try
+ {
+ minSdkVersion = Integer.parseInt(minSdkVersionStr);
+ }
+ catch (Exception e)
+ {
+ // the projectAPILevel will be used and minSdkVersion will be ignored
+ minSdkVersion = projectAPILevel;
+ }
+ String projectTarget = SdkUtils.getTargetNameForProject(project);
+
+ // if the instance is an emulator add the instance only if they have the same target and at least the same APILevel
+ if (instance instanceof IAndroidEmulatorInstance)
+ {
+ IAndroidEmulatorInstance emulatorInstance = (IAndroidEmulatorInstance) instance;
+ int emulatorApi = emulatorInstance.getAPILevel();
+ String emulatorTarget = emulatorInstance.getTarget();
+
+ if (emulatorApi >= minSdkVersion)
+ {
+ String emulatorInstanceName = emulatorInstance.getName();
+ String emulatorInstanceBaseTarget = SdkUtils.getBaseTarget(emulatorInstanceName);
+ boolean isEmulatorTargetAPlatform = SdkUtils.isPlatformTarget(emulatorInstanceName);
+
+ // if they have same target its ok
+ if (emulatorTarget.equals(projectTarget))
+ {
+ compatible = Status.OK_STATUS;
+ }
+ //if the emulator isn't a platform, but the base target is the same as the project, everything is ok
+ else if (!isEmulatorTargetAPlatform
+ && emulatorInstanceBaseTarget.equals(projectTarget))
+ {
+ compatible = Status.OK_STATUS;
+ }
+ else
+ {
+ compatible =
+ new Status(IStatus.WARNING, LaunchPlugin.PLUGIN_ID, NLS.bind(
+ LaunchNLS.UI_LaunchConfigurationTab_WARN_DEVICE_INCOMPATIBLE,
+ emulatorApi, projectAPILevel));
+ }
+ }
+ else
+ {
+ compatible =
+ new Status(IStatus.ERROR, LaunchPlugin.PLUGIN_ID, NLS.bind(
+ LaunchNLS.UI_LaunchConfigurationTab_ERR_EMULATOR_INCOMPATIBLE,
+ emulatorTarget, projectTarget));
+ }
+ }
+ else
+ {
+ if (instance != null)
+ {
+ int deviceSdkVersion = -1;
+ int tries = 0;
+
+ //wait the device to be online
+ while ((tries < 5) && (deviceSdkVersion <= 0))
+ {
+ try
+ {
+ deviceSdkVersion =
+ Integer.parseInt(DDMSFacade.getDeviceProperty(
+ instance.getSerialNumber(), "ro.build.version.sdk"));
+ }
+ catch (NumberFormatException e)
+ {
+ deviceSdkVersion = 0;
+ try
+ {
+ Thread.sleep(100);
+ }
+ catch (InterruptedException e1)
+ {
+ //do nothing
+ }
+ }
+ tries++;
+ }
+
+ if (deviceSdkVersion < minSdkVersion)
+ {
+ compatible =
+ new Status(IStatus.ERROR, LaunchPlugin.PLUGIN_ID, NLS.bind(
+ LaunchNLS.UI_LaunchConfigurationTab_ERR_DEVICE_INCOMPATIBLE,
+ deviceSdkVersion, projectAPILevel));
+ }
+ else if (deviceSdkVersion == projectAPILevel)
+ {
+ if (!isProjectTargetAPlatform)
+ {
+ compatible =
+ new Status(
+ IStatus.WARNING,
+ LaunchPlugin.PLUGIN_ID,
+ LaunchNLS.UI_LaunchConfigurationTab_WARN_DEVICE_TARGET_MISSING);
+ }
+ else
+ {
+ compatible = Status.OK_STATUS;
+ }
+ }
+ else
+ {
+ compatible =
+ new Status(IStatus.WARNING, LaunchPlugin.PLUGIN_ID, NLS.bind(
+ LaunchNLS.UI_LaunchConfigurationTab_WARN_DEVICE_INCOMPATIBLE,
+ deviceSdkVersion, projectAPILevel));
+ }
+ }
+
+ }
+ return compatible;
+ }
+
+ /**
+ * Filter instances the compatible with the given project
+ * @param project whose compatible instances need to be retrieved
+ * @return a new collection containing only the instances that are compatible with the given project
+ **/
+ public static Collection<ISerialNumbered> filterInstancesByProject(
+ Collection<ISerialNumbered> allInstances, IProject project)
+ {
+ Collection<ISerialNumbered> filteredInstances = new LinkedList<ISerialNumbered>();
+
+ for (ISerialNumbered instance : allInstances)
+ {
+ IStatus compatible = LaunchUtils.isCompatible(project, instance);
+
+ if (compatible.getSeverity() != IStatus.ERROR)
+ {
+ filteredInstances.add(instance);
+ }
+ }
+
+ return filteredInstances;
+ }
+
+} \ No newline at end of file
diff --git a/src/plugins/launch/src/com/motorola/studio/android/launch/StudioAndroidConfigurationDelegate.java b/src/plugins/launch/src/com/motorola/studio/android/launch/StudioAndroidConfigurationDelegate.java
new file mode 100644
index 0000000..aec89e5
--- /dev/null
+++ b/src/plugins/launch/src/com/motorola/studio/android/launch/StudioAndroidConfigurationDelegate.java
@@ -0,0 +1,762 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.motorola.studio.android.launch;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.debug.ui.ILaunchGroup;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.sequoyah.device.framework.model.IInstance;
+import org.eclipse.sequoyah.device.framework.model.handler.ServiceHandler;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.console.ConsolePlugin;
+import org.eclipse.ui.console.IConsole;
+
+import com.android.ddmlib.AndroidDebugBridge.IClientChangeListener;
+import com.android.ddmlib.Client;
+import com.android.ddmlib.ClientData;
+import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.internal.launch.AndroidLaunch;
+import com.android.ide.eclipse.adt.internal.launch.AndroidLaunchController;
+import com.android.ide.eclipse.adt.internal.launch.LaunchConfigDelegate;
+import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
+import com.android.ide.eclipse.adt.internal.sdk.Sdk;
+import com.android.ide.eclipse.adt.io.IFolderWrapper;
+import com.android.sdklib.xml.AndroidManifestParser;
+import com.android.sdklib.xml.ManifestData;
+import com.android.sdklib.xml.ManifestData.Activity;
+import com.motorola.studio.android.adt.DDMSFacade;
+import com.motorola.studio.android.adt.SdkUtils;
+import com.motorola.studio.android.adt.StudioAndroidEventManager;
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.common.preferences.DialogWithToggleUtils;
+import com.motorola.studio.android.emulator.EmulatorPlugin;
+import com.motorola.studio.android.emulator.core.devfrm.DeviceFrameworkManager;
+import com.motorola.studio.android.emulator.core.model.IAndroidEmulatorInstance;
+import com.motorola.studio.android.launch.i18n.LaunchNLS;
+import com.motorola.studio.android.launch.ui.StartedInstancesDialog;
+
+/**
+ * DESCRIPTION: This class is responsible to execute the launch process <br>
+ * RESPONSIBILITY: Perform application launch on a device. <br>
+ * COLABORATORS: none <br>
+ */
+@SuppressWarnings("restriction")
+public class StudioAndroidConfigurationDelegate extends LaunchConfigDelegate
+{
+
+ private static final String ERRONEOUS_LAUNCH_CONFIGURATION = "erroneous.launch.config.dialog";
+
+ private static final String NO_COMPATIBLE_DEVICE = "no.compatible.device.dialog";
+
+ IAndroidEmulatorInstance compatibleInstance = null;
+
+ IAndroidEmulatorInstance initialEmulatorInstance = null;
+
+ public List<Client> waitingDebugger = new ArrayList<Client>();
+
+ private class RunAsClientListener implements IClientChangeListener
+ {
+ /**
+ *
+ */
+ private final IAndroidEmulatorInstance instance;
+
+ /**
+ *
+ */
+ private final String appToLaunch;
+
+ /**
+ *
+ * @param instance
+ */
+ RunAsClientListener(IAndroidEmulatorInstance instance, String appToLaunch)
+ {
+ this.instance = instance;
+ this.appToLaunch = appToLaunch;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see com.android.ddmlib.AndroidDebugBridge.IClientChangeListener#clientChanged(com.android.ddmlib.Client, int)
+ */
+ public void clientChanged(Client client, int changeMask)
+ {
+ if ((changeMask & Client.CHANGE_NAME) == Client.CHANGE_NAME)
+ {
+ String applicationName = client.getClientData().getClientDescription();
+ if (applicationName != null)
+ {
+ IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore();
+ String home = store.getString(AdtPrefs.PREFS_HOME_PACKAGE);
+ if (home.equals(applicationName))
+ {
+ String serialNumber = client.getDevice().getSerialNumber();
+ String avdName = DDMSFacade.getNameBySerialNumber(serialNumber);
+ if ((instance != null) && instance.getName().equals(avdName))
+ {
+ StudioLogger.info(StudioAndroidConfigurationDelegate.class,
+ "Delegating launch session to ADT... ");
+
+ synchronized (StudioAndroidConfigurationDelegate.this)
+ {
+ StudioAndroidConfigurationDelegate.this.notify();
+ }
+ }
+ }
+
+ Client removeClient = null;
+ for (Client waiting : waitingDebugger)
+ {
+ int pid = waiting.getClientData().getPid();
+ if (pid == client.getClientData().getPid())
+ {
+ client.getDebuggerListenPort();
+ synchronized (StudioAndroidConfigurationDelegate.this)
+ {
+ StudioAndroidConfigurationDelegate.this.notify();
+ }
+ removeClient = waiting;
+ break;
+ }
+ }
+
+ if (removeClient != null)
+ {
+ waitingDebugger.remove(removeClient);
+ }
+ }
+ }
+
+ if ((changeMask & Client.CHANGE_DEBUGGER_STATUS) == Client.CHANGE_DEBUGGER_STATUS)
+ {
+ ClientData clientData = client.getClientData();
+ String applicationName = clientData.getClientDescription();
+ if (clientData.getDebuggerConnectionStatus() == ClientData.DebuggerStatus.DEFAULT)
+ {
+ if (((appToLaunch != null) && (applicationName != null))
+ && applicationName.equals(appToLaunch.substring(0,
+ appToLaunch.lastIndexOf("."))))
+ {
+ client.getDebuggerListenPort();
+ synchronized (StudioAndroidConfigurationDelegate.this)
+ {
+ StudioAndroidConfigurationDelegate.this.notify();
+ }
+ }
+ else if (appToLaunch != null)
+ {
+ waitingDebugger.add(client);
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.debug.core.model.LaunchConfigurationDelegate#preLaunchCheck(org.eclipse.debug.core.ILaunchConfiguration, java.lang.String, org.eclipse.core.runtime.IProgressMonitor)
+ */
+ @Override
+ public boolean preLaunchCheck(ILaunchConfiguration configuration, String mode,
+ IProgressMonitor monitor) throws CoreException
+ {
+ initialEmulatorInstance = null;
+ boolean isOk = super.preLaunchCheck(configuration, mode, monitor);
+
+ if (isOk)
+ {
+ final String instanceName =
+ configuration.getAttribute(
+ ILaunchConfigurationConstants.ATTR_DEVICE_INSTANCE_NAME, (String) null);
+
+ // we found an instance
+ if ((instanceName != null) && (instanceName.length() > 0))
+ {
+ IAndroidEmulatorInstance instance =
+ DeviceFrameworkManager.getInstance().getInstanceByName(instanceName);
+ if (instance == null)
+ {
+ String serialNumber = LaunchUtils.getSerialNumberForInstance(instanceName);
+ if (!DDMSFacade.isDeviceOnline(serialNumber))
+ {
+ isOk = false;
+ handleErrorDuringLaunch(configuration, mode, instanceName);
+ }
+ }
+ else
+ {
+ if (!instance.isAvailable())
+ {
+ isOk = false;
+ handleErrorDuringLaunch(configuration, mode, instanceName);
+ }
+
+ if (!instance.isStarted())
+ {
+ initialEmulatorInstance = instance;
+ //updates the compatible instance with user response
+ isOk = checkForCompatibleRunningInstances(configuration);
+ }
+ }
+ }
+ else
+ {
+ isOk = false;
+ handleErrorDuringLaunch(configuration, mode, null);
+ }
+ }
+ // validate if the project isn't a library project
+ if (isOk)
+ {
+ String projectName =
+ configuration.getAttribute(ILaunchConfigurationConstants.ATTR_PROJECT_NAME,
+ (String) null);
+ if (projectName != null)
+ {
+ IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
+ if ((project != null) && SdkUtils.isLibraryProject(project))
+ {
+ handleProjectError(configuration, project, mode);
+ isOk = false;
+ }
+ }
+ }
+
+ return isOk;
+ }
+
+ private void handleProjectError(final ILaunchConfiguration config, final IProject project,
+ final String mode)
+ {
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable()
+ {
+
+ public void run()
+ {
+ Shell shell = LaunchUtils.getActiveWorkbenchShell();
+
+ String message = LaunchNLS.UI_LaunchConfigurationTab_ERR_PROJECT_IS_LIBRARY;
+
+ String prefKey = ERRONEOUS_LAUNCH_CONFIGURATION;
+
+ DialogWithToggleUtils.showInformation(prefKey,
+ LaunchNLS.ERR_LaunchConfigurationShortcut_MsgTitle, message);
+
+ StructuredSelection struturedSelection;
+
+ String groupId = IDebugUIConstants.ID_RUN_LAUNCH_GROUP;
+
+ ILaunchGroup group = DebugUITools.getLaunchGroup(config, mode);
+ groupId = group.getIdentifier();
+ struturedSelection = new StructuredSelection(config);
+
+ DebugUITools.openLaunchConfigurationDialogOnGroup(shell, struturedSelection,
+ groupId);
+ }
+ });
+ }
+
+ private void handleErrorDuringLaunch(final ILaunchConfiguration config, final String mode,
+ final String instanceName)
+ {
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable()
+ {
+
+ public void run()
+ {
+ Shell shell = LaunchUtils.getActiveWorkbenchShell();
+
+ String message =
+ instanceName != null ? NLS.bind(
+ LaunchNLS.ERR_LaunchDelegate_InvalidDeviceInstance, instanceName)
+ : NLS.bind(LaunchNLS.ERR_LaunchDelegate_No_Compatible_Device,
+ config.getName());
+
+ String prefKey =
+ instanceName != null ? ERRONEOUS_LAUNCH_CONFIGURATION
+ : NO_COMPATIBLE_DEVICE;
+
+ DialogWithToggleUtils.showInformation(prefKey,
+ LaunchNLS.ERR_LaunchConfigurationShortcut_MsgTitle, message);
+
+ StructuredSelection struturedSelection;
+
+ String groupId = IDebugUIConstants.ID_RUN_LAUNCH_GROUP;
+
+ ILaunchGroup group = DebugUITools.getLaunchGroup(config, mode);
+ groupId = group.getIdentifier();
+ struturedSelection = new StructuredSelection(config);
+
+ DebugUITools.openLaunchConfigurationDialogOnGroup(shell, struturedSelection,
+ groupId);
+ }
+ });
+ }
+
+ /**
+ * Launches an Android application based on the given launch configuration.
+ */
+ @Override
+ public void launch(ILaunchConfiguration configuration, String mode, ILaunch launch,
+ IProgressMonitor monitor) throws CoreException
+
+ {
+ //use a working copy because it can be changed and these changes should not be propagated to the original copy
+ ILaunchConfigurationWorkingCopy configurationWorkingCopy = configuration.getWorkingCopy();
+
+ StudioLogger.info(StudioAndroidConfigurationDelegate.class,
+ "Launch Android Application using Studio for Android wizard. Configuration: "
+ + configurationWorkingCopy + " mode:" + mode + " launch: " + launch);
+ try
+ {
+
+ String projectName =
+ configurationWorkingCopy.getAttribute(
+ ILaunchConfigurationConstants.ATTR_PROJECT_NAME, (String) null);
+ int launchAction =
+ configurationWorkingCopy.getAttribute(
+ ILaunchConfigurationConstants.ATTR_LAUNCH_ACTION,
+ ILaunchConfigurationConstants.ATTR_LAUNCH_ACTION_DEFAULT);
+
+ String instanceName =
+ configurationWorkingCopy.getAttribute(
+ ILaunchConfigurationConstants.ATTR_DEVICE_INSTANCE_NAME, (String) null);
+
+ if ((projectName != null) && (instanceName != null))
+ {
+ IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
+ if (project == null)
+ {
+ IStatus status =
+ new Status(Status.ERROR, LaunchPlugin.PLUGIN_ID,
+ "Could not retrieve project: " + projectName);
+ throw new CoreException(status);
+ }
+
+ String appToLaunch = null;
+ if (launchAction == ILaunchConfigurationConstants.ATTR_LAUNCH_ACTION_DEFAULT)
+ {
+ ManifestData manifestParser =
+ AndroidManifestParser.parse(new IFolderWrapper(project));
+ Activity launcherActivity = manifestParser.getLauncherActivity();
+ String activityName = null;
+ if (launcherActivity != null)
+ {
+ activityName = launcherActivity.getName();
+ }
+
+ // if there's no default activity. Then there's nothing to be launched.
+ if (activityName != null)
+ {
+ appToLaunch = activityName;
+ }
+ }
+ // case for a specific activity
+ else if (launchAction == ILaunchConfigurationConstants.ATTR_LAUNCH_ACTION_ACTIVITY)
+ {
+ appToLaunch =
+ configurationWorkingCopy.getAttribute(
+ ILaunchConfigurationConstants.ATTR_ACTIVITY, (String) null);
+
+ if ((appToLaunch == null) || "".equals(appToLaunch))
+ {
+ IStatus status =
+ new Status(
+ Status.ERROR,
+ LaunchPlugin.PLUGIN_ID,
+ "Activity field cannot be empty. Specify an activity or use the default activity on launch configuration.");
+ throw new CoreException(status);
+ }
+ }
+ // for the do nothing case there is nothing to do
+
+ IAndroidEmulatorInstance emuInstance =
+ DeviceFrameworkManager.getInstance().getInstanceByName(instanceName);
+
+ RunAsClientListener list = null;
+
+ //if initialEmulatorInstance is not null it means that it was offline and user has interacted with StartedInstancesDialog.
+ //The emuInstance variable should be overrided by the initialEmulatorInstance because the emuInstance can be the new
+ //user choice (in case he has selected the check box in dialog asking to update the run configuration)
+ if (initialEmulatorInstance != null)
+ {
+ emuInstance = initialEmulatorInstance;
+ }
+
+ try
+ {
+ if (appToLaunch != null)
+ {
+ list = new RunAsClientListener(emuInstance, appToLaunch);
+ StudioAndroidEventManager.asyncAddClientChangeListener(list);
+ }
+
+ // The instance from the launch configuration is an emulator (because the query returned
+ // something different from null) and is not started.
+ if ((emuInstance != null) && (!emuInstance.isStarted()))
+ {
+ if (compatibleInstance != null)
+ {
+ emuInstance = compatibleInstance;
+ instanceName = emuInstance.getName();
+ configurationWorkingCopy.setAttribute(
+ ILaunchConfigurationConstants.ATTR_DEVICE_INSTANCE_NAME,
+ emuInstance.getName());
+ configurationWorkingCopy.setAttribute(
+ ILaunchConfigurationConstants.ATTR_ADT_DEVICE_INSTANCE_NAME,
+ emuInstance.getName());
+ }
+ else
+ {
+ startEmuInstance(emuInstance);
+ }
+ }
+
+ StudioLogger.info(StudioAndroidConfigurationDelegate.class,
+ "AVD where the application will be executed: " + instanceName);
+
+
+ String serialNumber = LaunchUtils.getSerialNumberForInstance(instanceName);
+ if (serialNumber == null)
+ {
+ IStatus status =
+ new Status(Status.ERROR, LaunchPlugin.PLUGIN_ID,
+ "Could not retrieve AVD instance: " + instanceName);
+ throw new CoreException(status);
+ }
+
+ bringConsoleView();
+
+ // Determining if it is an emulator or handset and creating the description
+ //to be used for usage data collection
+ String descriptionToLog = "";
+ if (emuInstance != null)
+ {
+ descriptionToLog = StudioLogger.VALUE_EMULATOR;
+ }
+ else
+ {
+ if ((serialNumber != null) && (!serialNumber.equals("")))
+ {
+ descriptionToLog = StudioLogger.VALUE_HANDSET;
+ }
+ }
+
+ if (!descriptionToLog.equals(""))
+ {
+ descriptionToLog =
+ StudioLogger.KEY_DEVICE_TYPE + descriptionToLog
+ + StudioLogger.SEPARATOR;
+ }
+
+ descriptionToLog = descriptionToLog + StudioLogger.KEY_USE_VDL;
+
+ descriptionToLog = descriptionToLog + StudioLogger.VALUE_NO;
+ super.launch(configurationWorkingCopy, mode, launch, monitor);
+
+ // Collecting usage data for statistical purposes
+ try
+ {
+ String prjTarget = "";
+ if (project != null)
+ {
+ prjTarget = Sdk.getCurrent().getTarget(project).getName();
+ }
+
+ if (!descriptionToLog.equals(""))
+ {
+ descriptionToLog = descriptionToLog + StudioLogger.SEPARATOR;
+ }
+
+ descriptionToLog =
+ descriptionToLog + StudioLogger.KEY_PRJ_TARGET + prjTarget;
+
+ if (emuInstance != null)
+ {
+ String emuTarget = emuInstance.getTarget();
+ descriptionToLog = descriptionToLog + StudioLogger.SEPARATOR;
+ descriptionToLog =
+ descriptionToLog + StudioLogger.KEY_TARGET + emuTarget;
+ }
+
+ StudioLogger.collectUsageData(mode, StudioLogger.KIND_APP_MANAGEMENT,
+ descriptionToLog, LaunchPlugin.PLUGIN_ID, LaunchPlugin.getDefault()
+ .getBundle().getVersion().toString());
+ }
+ catch (Throwable e)
+ {
+ //Do nothing, but error on the log should never prevent app from working
+ }
+
+ }
+ finally
+ {
+ if (list != null)
+ {
+ StudioAndroidEventManager.asyncRemoveClientChangeListener(list);
+ }
+ StudioAndroidEventManager.asyncAddClientChangeListener(AndroidLaunchController
+ .getInstance());
+ }
+ }
+ else
+ {
+ throw new CoreException(new Status(IStatus.ERROR, LaunchPlugin.PLUGIN_ID,
+ "Missing parameters for launch"));
+ }
+ }
+ catch (CoreException e)
+ {
+ AndroidLaunch androidLaunch = (AndroidLaunch) launch;
+ androidLaunch.stopLaunch();
+ StudioLogger.error(StudioAndroidConfigurationDelegate.class, "Error while lauching "
+ + configurationWorkingCopy.getName(), e);
+ throw e;
+ }
+ catch (Exception e)
+ {
+ StudioLogger.error(LaunchUtils.class,
+ "An error occurred trying to parse AndroidManifest", e);
+ }
+ finally
+ {
+ if (mode.equals(ILaunchManager.RUN_MODE))
+ {
+ AndroidLaunch androidLaunch = (AndroidLaunch) launch;
+ androidLaunch.stopLaunch();
+ }
+ }
+ }
+
+ /**
+ * @param project
+ * @param emuInstance
+ * @throws CoreException
+ */
+ private boolean checkForCompatibleRunningInstances(ILaunchConfiguration configuration)
+ throws CoreException
+ {
+ IProject project = null;
+ compatibleInstance = null;
+
+ final String projectName =
+ configuration.getAttribute(ILaunchConfigurationConstants.ATTR_PROJECT_NAME,
+ (String) null);
+
+ project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
+ if (project == null)
+ {
+ IStatus status =
+ new Status(Status.ERROR, LaunchPlugin.PLUGIN_ID, "Could not retrieve project: "
+ + projectName);
+ throw new CoreException(status);
+ }
+
+ //Check if there is a compatible instance running to launch the app
+ Collection<IAndroidEmulatorInstance> startedInstances =
+ DeviceFrameworkManager.getInstance().getAllStartedInstances();
+
+ final Collection<IAndroidEmulatorInstance> compatibleStartedInstances =
+ new HashSet<IAndroidEmulatorInstance>();
+
+ boolean continueLaunch = true;
+
+ for (IAndroidEmulatorInstance i : startedInstances)
+ {
+ IStatus resultStatus = LaunchUtils.isCompatible(project, i.getName());
+ if ((resultStatus.getSeverity() == Status.OK)
+ || (resultStatus.getSeverity() == Status.WARNING))
+ {
+ compatibleStartedInstances.add(i);
+ }
+ }
+ if (compatibleStartedInstances.size() > 0)
+ {
+ //show a dialog with compatible running instances so the user can
+ //choose one to run the app, or he can choose to run the preferred AVD
+
+ StartedInstancesDialogProxy proxy =
+ new StartedInstancesDialogProxy(compatibleStartedInstances, configuration,
+ project);
+ PlatformUI.getWorkbench().getDisplay().syncExec(proxy);
+
+ compatibleInstance = proxy.getSelectedInstance();
+ continueLaunch = proxy.continueLaunch();
+ }
+ return continueLaunch;
+ }
+
+ private class StartedInstancesDialogProxy implements Runnable
+ {
+ private IAndroidEmulatorInstance selectedInstance = null;
+
+ private boolean continueLaunch = true;
+
+ private final ILaunchConfiguration configuration;
+
+ Collection<IAndroidEmulatorInstance> compatibleStartedInstances = null;
+
+ IProject project = null;
+
+ /**
+ *
+ */
+ public StartedInstancesDialogProxy(
+ Collection<IAndroidEmulatorInstance> compatibleStartedInstances,
+ ILaunchConfiguration configuration, IProject project)
+ {
+ this.compatibleStartedInstances = compatibleStartedInstances;
+ this.configuration = configuration;
+ this.project = project;
+ }
+
+ public void run()
+ {
+ Shell aShell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+ Shell shell = new Shell(aShell);
+ StartedInstancesDialog dialog;
+ try
+ {
+ dialog =
+ new StartedInstancesDialog(shell, compatibleStartedInstances,
+ configuration, project);
+ dialog.setBlockOnOpen(true);
+ dialog.open();
+
+ selectedInstance = null;
+ if (dialog.getReturnCode() == IDialogConstants.OK_ID)
+ {
+ selectedInstance = dialog.getSelectedInstance();
+ }
+ else if (dialog.getReturnCode() == IDialogConstants.ABORT_ID)
+ {
+ continueLaunch = false;
+ }
+ }
+ catch (CoreException e)
+ {
+ StudioLogger.error(StudioAndroidConfigurationDelegate.class,
+ "It was not possible to open Started Instance Dialog", e);
+ }
+ }
+
+ public IAndroidEmulatorInstance getSelectedInstance()
+ {
+ return selectedInstance;
+ }
+
+ public boolean continueLaunch()
+ {
+ return continueLaunch;
+ }
+ }
+
+ /**
+ * Bring Console View to the front and activate the appropriate stream
+ *
+ */
+ private void bringConsoleView()
+ {
+ IConsole activeConsole = null;
+
+ IConsole[] consoles = ConsolePlugin.getDefault().getConsoleManager().getConsoles();
+ for (IConsole console : consoles)
+ {
+ if (console.getName().equals(ILaunchConfigurationConstants.ANDROID_CONSOLE_ID))
+ {
+ activeConsole = console;
+ }
+ }
+
+ // Bring Console View to the front
+ if (activeConsole != null)
+ {
+ ConsolePlugin.getDefault().getConsoleManager().showConsoleView(activeConsole);
+ }
+
+ }
+
+ /**
+ *
+ * @param instance
+ * @throws CoreException
+ */
+ private void startEmuInstance(IAndroidEmulatorInstance instance) throws CoreException
+ {
+ StudioLogger.info(StudioAndroidConfigurationDelegate.class,
+ "Needs to Start the AVD instance before launching... ");
+
+ ServiceHandler startHandler = EmulatorPlugin.getStartServiceHandler();
+ IStatus status = startHandler.run((IInstance) instance, null, new NullProgressMonitor());
+
+ StudioLogger.info(StudioAndroidConfigurationDelegate.class,
+ "Status of the launch service: " + status);
+
+ if (status.getSeverity() == Status.ERROR)
+ {
+ throw new CoreException(status);
+ }
+ else if (status.getSeverity() == Status.CANCEL)
+ {
+ StudioLogger.info(StudioAndroidConfigurationDelegate.class,
+ "Abort launch session because the AVD start was canceled. ");
+ return;
+ }
+
+ if (!instance.isStarted())
+ {
+ status =
+ new Status(Status.ERROR, LaunchPlugin.PLUGIN_ID,
+ "The Android Virtual Device is not started: " + instance.getName());
+ throw new CoreException(status);
+ }
+
+ synchronized (this)
+ {
+ try
+ {
+ wait();
+ }
+ catch (InterruptedException e)
+ {
+ StudioLogger.info("Could not wait: ", e.getMessage());
+ }
+ }
+ }
+}
diff --git a/src/plugins/launch/src/com/motorola/studio/android/launch/i18n/LaunchNLS.java b/src/plugins/launch/src/com/motorola/studio/android/launch/i18n/LaunchNLS.java
new file mode 100644
index 0000000..9894057
--- /dev/null
+++ b/src/plugins/launch/src/com/motorola/studio/android/launch/i18n/LaunchNLS.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.motorola.studio.android.launch.i18n;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * DESCRIPTION: This class is the NLS component for Launch plugin. It is the
+ * main class for internationalization
+ *
+ * RESPONSIBILITY: Provide local strings for using throughout the tool
+ *
+ * COLABORATORS: messages.properties: file that contains the strings that will
+ * be provided to the plugin
+ *
+ * USAGE: Use any of the public static variables for accessing the local strings
+ */
+public class LaunchNLS extends NLS
+{
+ /**
+ * The bundle location. It refers to messages.properties file inside this
+ * package
+ */
+
+ static
+ {
+ LaunchNLS.initializeMessages("com.motorola.studio.android.launch.i18n.launchNLS",
+ LaunchNLS.class);
+ }
+
+ /*
+ * UI string area
+ */
+
+ public static String LaunchComposite_UI_LaunchComposite_DestinationGroupText;
+
+ public static String LaunchConfigurationTab_CreateNewAVDLink;
+
+ public static String LaunchConfigurationTab_DoNothingButton;
+
+ public static String LaunchConfigurationTab_LaunchButton;
+
+ public static String UI_LaunchComposite_ProjectNameLabel;
+
+ public static String UI_LaunchComposite_ActivityDefaultButton;
+
+ public static String UI_LaunchComposite_ActivityGroupLabel;
+
+ public static String UI_LaunchComposite_DeviceNameLabel;
+
+ public static String UI_LaunchComposite_BrowseButton;
+
+ public static String UI_LaunchComposite_ProjectRequiredMessage;
+
+ public static String UI_LaunchComposite_ProjectRequiredTitle;
+
+ public static String UI_LaunchComposite_SelectProjectScreenTitle;
+
+ public static String UI_LaunchComposite_SelectProjectScreenMessage;
+
+ public static String UI_LaunchComposite_SelectActivityScreenTitle;
+
+ public static String UI_LaunchComposite_SelectActivityScreenMessage;
+
+ public static String UI_LaunchComposite_SelectDeviceScreenTitle;
+
+ public static String UI_LaunchComposite_SelectDeviceScreenMessage;
+
+ public static String UI_LaunchConfigurationTab_ERR_DEVICE_INEXISTENT;
+
+ public static String UI_LaunchConfigurationTab_ERR_DEVICE_INCOMPATIBLE;
+
+ public static String UI_LaunchConfigurationTab_ERR_INVALID_ACTIVITY;
+
+ public static String UI_LaunchConfigurationTab_ERR_ACTIVITY_NOT_EXIST;
+
+ public static String UI_LaunchConfigurationTab_ERR_PROJECT_NOT_EXIST;
+
+ public static String UI_LaunchConfigurationTab_WARN_DEVICE_INCOMPATIBLE;
+
+ public static String UI_LaunchConfigurationTab_Tab_Name;
+
+ public static String UI_LaunchConfigurationTab_InfoSelectInstance;
+
+ public static String UI_LaunchConfigurationTab_InfoSelectActivity;
+
+ public static String UI_LaunchConfigurationTab_InfoSelectProject;
+
+ public static String ERR_LaunchConfigurationShortcut_MsgTitle;
+
+ public static String ERR_LaunchConfigurationShortcut_CannotLaunchSelectedResourceMsg;
+
+ public static String ERR_LaunchDelegate_InvalidDeviceInstance;
+
+ public static String ERR_LaunchDelegate_No_Compatible_Device;
+
+ public static String UI_LaunchConfigurationTab_ERR_EMULATOR_INCOMPATIBLE;
+
+ public static String UI_LaunchConfigurationTab_WARN_DEVICE_TARGET_MISSING;
+
+ public static String UI_LaunchConfigurationTab_ERR_PROJECT_IS_LIBRARY;
+
+ public static String UI_StartedInstancesDialog_CompatibleAvdsColumnName;
+
+ public static String UI_StartedInstancesDialog_Message;
+
+ public static String UI_StartedInstancesDialog_Title;
+
+ public static String UI_StartedInstancesDialog_WindowTitle;
+
+ public static String UI_StartedInstancesDialog_ApiLevel;
+
+ public static String UI_StartedInstancesDialog_Tooltip;
+
+ public static String UI_StartedInstancesDialog_UpdateRunConfigurarion;
+}
diff --git a/src/plugins/launch/src/com/motorola/studio/android/launch/i18n/launchNLS.properties b/src/plugins/launch/src/com/motorola/studio/android/launch/i18n/launchNLS.properties
new file mode 100644
index 0000000..6a7113f
--- /dev/null
+++ b/src/plugins/launch/src/com/motorola/studio/android/launch/i18n/launchNLS.properties
@@ -0,0 +1,57 @@
+#
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+#
+# 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.
+#
+
+LaunchComposite_UI_LaunchComposite_DestinationGroupText=Basic settings
+LaunchConfigurationTab_CreateNewAVDLink=<a>Create new AVD...</a>
+LaunchConfigurationTab_DoNothingButton=Do Nothing
+LaunchConfigurationTab_LaunchButton=Launch:
+UI_LaunchComposite_ProjectNameLabel=Project:
+UI_LaunchComposite_ActivityGroupLabel=Activity
+UI_LaunchComposite_DeviceNameLabel=Device:
+UI_LaunchComposite_BrowseButton=Browse
+UI_LaunchComposite_ActivityDefaultButton=Launch Default Activity
+UI_LaunchComposite_ProjectRequiredMessage=A project must be selected before browsing for an activity
+UI_LaunchComposite_ProjectRequiredTitle=Project required
+UI_LaunchComposite_SelectProjectScreenTitle=Project Selection
+UI_LaunchComposite_SelectProjectScreenMessage=Select a project
+UI_LaunchComposite_SelectActivityScreenTitle=Activity Selection
+UI_LaunchComposite_SelectActivityScreenMessage=Select an activity
+UI_LaunchComposite_SelectDeviceScreenTitle=Device Selection
+UI_LaunchComposite_SelectDeviceScreenMessage=Select a device instance
+UI_LaunchConfigurationTab_ERR_DEVICE_INEXISTENT=The selected device instance does not exist or is invalid.
+UI_LaunchConfigurationTab_ERR_DEVICE_INCOMPATIBLE=The selected device instance is not compatible. Its API level is {0} while the project API level is {1}
+UI_LaunchConfigurationTab_ERR_EMULATOR_INCOMPATIBLE=The selected device instance is not compatible. Its Device target is {0} while the Project target is {1}
+UI_LaunchConfigurationTab_ERR_INVALID_ACTIVITY=The selected file is not a valid activity.
+UI_LaunchConfigurationTab_ERR_ACTIVITY_NOT_EXIST=The selected activity does not exist.
+UI_LaunchConfigurationTab_ERR_PROJECT_NOT_EXIST=The selected project does not exist.
+UI_LaunchConfigurationTab_ERR_PROJECT_IS_LIBRARY=Cannot launch library projects.
+UI_LaunchConfigurationTab_WARN_DEVICE_INCOMPATIBLE=The selected device instance has an API level ({0}) higher than the project API level ({1})
+UI_LaunchConfigurationTab_WARN_DEVICE_TARGET_MISSING=The selected instance isn't an emulator and its target cannot be checked
+UI_LaunchConfigurationTab_Tab_Name=Main
+UI_LaunchConfigurationTab_InfoSelectInstance=Select a device instance
+UI_LaunchConfigurationTab_InfoSelectActivity=Select an activity
+UI_LaunchConfigurationTab_InfoSelectProject=Select a project
+UI_StartedInstancesDialog_CompatibleAvdsColumnName=Compatible online AVDs
+UI_StartedInstancesDialog_Message=Select an online AVD instance and click OK to launch the project in that AVD. \nClick Ignore to start the preferred AVD, or click Abort to cancel the launch.
+UI_StartedInstancesDialog_Title=AVD "{0}" is offline.
+UI_StartedInstancesDialog_WindowTitle=Preferred AVD offline
+UI_StartedInstancesDialog_ApiLevel=API Level
+UI_StartedInstancesDialog_Tooltip=The project and device API level are not an exact match
+UI_StartedInstancesDialog_UpdateRunConfigurarion=Update configuration to use selected AVD
+ERR_LaunchConfigurationShortcut_MsgTitle=MOTODEV Studio For Android
+ERR_LaunchConfigurationShortcut_CannotLaunchSelectedResourceMsg=The selected resource cannot be launched.
+ERR_LaunchDelegate_InvalidDeviceInstance=Device instance "{0}" does not exist or is not available.\nPlease verify and try again.
+ERR_LaunchDelegate_No_Compatible_Device=No compatible device instance was found to run "{0}". Review your configuration and try again. \ No newline at end of file
diff --git a/src/plugins/launch/src/com/motorola/studio/android/launch/ui/AndroidProjectsSelectionDialog.java b/src/plugins/launch/src/com/motorola/studio/android/launch/ui/AndroidProjectsSelectionDialog.java
new file mode 100644
index 0000000..c775271
--- /dev/null
+++ b/src/plugins/launch/src/com/motorola/studio/android/launch/ui/AndroidProjectsSelectionDialog.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.motorola.studio.android.launch.ui;
+
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.ElementListSelectionDialog;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
+
+import com.motorola.studio.android.launch.LaunchPlugin;
+import com.motorola.studio.android.launch.LaunchUtils;
+import com.motorola.studio.android.launch.i18n.LaunchNLS;
+
+/**
+ * DESCRIPTION:
+ * Selection Dialog with only opened MOTOMAGX projects
+ * <br>
+ * RESPONSIBILITY:
+ * Provides a Element Selection Dialog to select a MOTOMAGX project
+ * <br>
+ * COLABORATORS:
+ * none
+ * <br>
+ * USAGE:
+ * This should be instanced when the user must choose one of a MOTOMAGX project list
+ */
+public class AndroidProjectsSelectionDialog extends ElementListSelectionDialog
+{
+
+ private static final String PRJ_SELECTION_CONTEXT_HELP_ID =
+ LaunchPlugin.PLUGIN_ID + ".projectSelectionDialog";
+
+ /**
+ * Create a new Project Selection Dialog
+ * @param parent the parent shell
+ * @param renderer the label provider
+ */
+ public AndroidProjectsSelectionDialog(Shell parent, ILabelProvider renderer)
+ {
+ super(parent, renderer);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.dialogs.ElementListSelectionDialog#createDialogArea(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ protected Control createDialogArea(Composite parent)
+ {
+ Control control = super.createDialogArea(parent);
+
+ setHelpAvailable(true);
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(control, PRJ_SELECTION_CONTEXT_HELP_ID);
+ return control;
+ }
+
+ /**
+ * Creates a selection dialog with the workbench label provider
+ * @param parent The parent composite
+ */
+ public AndroidProjectsSelectionDialog(Shell parent)
+ {
+ super(parent, new WorkbenchLabelProvider());
+ }
+
+ /**
+ * Sets the default elements: the list of all opened Studio for Android projects
+ */
+ public void setDefaultElements()
+ {
+ this.setElements(LaunchUtils.getSupportedProjects());
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.dialogs.AbstractElementListSelectionDialog#open()
+ */
+ @Override
+ public int open()
+ {
+ this.setTitle(LaunchNLS.UI_LaunchComposite_SelectProjectScreenTitle);
+ this.setMessage(LaunchNLS.UI_LaunchComposite_SelectProjectScreenMessage);
+
+ setDefaultElements();
+ return super.open();
+ }
+}
diff --git a/src/plugins/launch/src/com/motorola/studio/android/launch/ui/DeviceSelectionDialog.java b/src/plugins/launch/src/com/motorola/studio/android/launch/ui/DeviceSelectionDialog.java
new file mode 100644
index 0000000..1659966
--- /dev/null
+++ b/src/plugins/launch/src/com/motorola/studio/android/launch/ui/DeviceSelectionDialog.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.motorola.studio.android.launch.ui;
+
+import java.util.Collection;
+import java.util.Properties;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.sequoyah.device.framework.model.IInstance;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.ElementListSelectionDialog;
+
+import com.motorola.studio.android.adt.ISerialNumbered;
+import com.motorola.studio.android.devices.DevicesManager;
+import com.motorola.studio.android.emulator.core.model.IAndroidEmulatorInstance;
+import com.motorola.studio.android.launch.LaunchPlugin;
+import com.motorola.studio.android.launch.LaunchUtils;
+import com.motorola.studio.android.launch.i18n.LaunchNLS;
+
+/**
+ * DESCRIPTION:
+ * This class implements the device selection dialog
+ *
+ * RESPONSIBILITY:
+ * Provides a dialog populated with the available device instances
+ *
+ * COLABORATORS:
+ * None.
+ *
+ * USAGE:
+ * This class is intended to be used by Eclipse only
+ */
+public class DeviceSelectionDialog extends ElementListSelectionDialog
+{
+ private static final String DEV_SELECTION_CONTEXT_HELP_ID = LaunchPlugin.PLUGIN_ID
+ + ".deviceSelectionDialog";
+
+ /**
+ * Default constructor
+ *
+ * @param parent Parent shell
+ * @param description Dialog description
+ */
+ public DeviceSelectionDialog(Shell parent, String description, final IProject project)
+ {
+ super(parent, new LabelProvider()
+ {
+ @Override
+ public String getText(Object element)
+ {
+ String result = "";
+ if (element instanceof ISerialNumbered)
+ {
+ ISerialNumbered serialNumbered = (ISerialNumbered) element;
+ result = serialNumbered.getDeviceName();
+ if (serialNumbered instanceof IAndroidEmulatorInstance)
+ {
+ IAndroidEmulatorInstance emulatorInstance =
+ (IAndroidEmulatorInstance) serialNumbered;
+ int emulatorApi = emulatorInstance.getAPILevel();
+ String emulatorTarget = emulatorInstance.getTarget();
+ result += " (" + emulatorTarget + ", Api version " + emulatorApi + ")";
+ }
+ else if (serialNumbered instanceof IInstance)
+ {
+ IInstance instance = (IInstance) serialNumbered;
+ Properties properties = instance.getProperties();
+ if (properties != null)
+ {
+ String target = properties.getProperty("ro.build.version.release"); //$NON-NLS-1$
+ if (target != null)
+ {
+ result += " (Android " + target + ")";
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public Image getImage(Object element)
+ {
+
+ Image img = null;
+
+ ISerialNumbered serialNumbered = (ISerialNumbered) element;
+ IStatus compatible = LaunchUtils.isCompatible(project, serialNumbered);
+
+ // notify the warning state
+ if (compatible.getSeverity() == IStatus.WARNING)
+ {
+ img =
+ PlatformUI.getWorkbench().getSharedImages()
+ .getImage(ISharedImages.IMG_OBJS_WARN_TSK);
+ }
+
+ return img;
+ }
+ });
+
+ this.setTitle(LaunchNLS.UI_LaunchComposite_SelectDeviceScreenTitle);
+ this.setMessage(description);
+
+ Collection<ISerialNumbered> instances = DevicesManager.getInstance().getAllDevicesSorted();
+ if ((project != null) && (instances != null) && (instances.size() > 0))
+ {
+ Collection<ISerialNumbered> filteredInstances =
+ LaunchUtils.filterInstancesByProject(instances, project);
+ Object[] filteredInstancesArray = filteredInstances.toArray();
+ this.setElements(filteredInstancesArray);
+ }
+
+ this.setHelpAvailable(true);
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, DEV_SELECTION_CONTEXT_HELP_ID);
+ }
+}
diff --git a/src/plugins/launch/src/com/motorola/studio/android/launch/ui/LaunchConfigurationTab.java b/src/plugins/launch/src/com/motorola/studio/android/launch/ui/LaunchConfigurationTab.java
new file mode 100644
index 0000000..1d68897
--- /dev/null
+++ b/src/plugins/launch/src/com/motorola/studio/android/launch/ui/LaunchConfigurationTab.java
@@ -0,0 +1,981 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.motorola.studio.android.launch.ui;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.ui.AbstractLaunchConfigurationTab;
+import org.eclipse.debug.ui.ILaunchConfigurationTab;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.sequoyah.device.framework.events.IInstanceListener;
+import org.eclipse.sequoyah.device.framework.events.InstanceEvent;
+import org.eclipse.sequoyah.device.framework.events.InstanceEventManager;
+import org.eclipse.sequoyah.device.framework.model.IInstance;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Link;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.ElementListSelectionDialog;
+import org.eclipse.ui.dialogs.ISelectionStatusValidator;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+import com.android.ide.eclipse.adt.io.IFolderWrapper;
+import com.android.sdklib.xml.AndroidManifestParser;
+import com.android.sdklib.xml.ManifestData;
+import com.android.sdklib.xml.ManifestData.Activity;
+import com.motorola.studio.android.adt.ISerialNumbered;
+import com.motorola.studio.android.adt.SdkUtils;
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.emulator.device.handlers.OpenNewDeviceWizardHandler;
+import com.motorola.studio.android.emulator.device.refresh.InstancesListRefresh;
+import com.motorola.studio.android.launch.ILaunchConfigurationConstants;
+import com.motorola.studio.android.launch.LaunchPlugin;
+import com.motorola.studio.android.launch.LaunchUtils;
+import com.motorola.studio.android.launch.i18n.LaunchNLS;
+
+/**
+ * DESCRIPTION: This class implements the tab that is shown when the user is
+ * editing the configuration to run a MOTODEV Studio for Android application
+ *
+ * RESPONSIBILITY: User interface to allow the user to enter information to
+ * launch the application.
+ *
+ * COLABORATORS: This class is one of the tabs of the
+ * LaunchConfigurationTabGroup
+ *
+ * USAGE: This class should be created/used by the LaunchConfigurationTabGroup
+ * only.
+ */
+@SuppressWarnings("restriction")
+public class LaunchConfigurationTab extends AbstractLaunchConfigurationTab
+{
+ private static final String NAME = LaunchNLS.UI_LaunchConfigurationTab_Tab_Name;
+
+ private static final Object UPDATE_WIDGETS_EVENT = new Object();
+
+ private Composite mainComposite;
+
+ private String projectName = ""; //$NON-NLS-1$
+
+ private String activityName = ""; //$NON-NLS-1$
+
+ private String deviceName = ""; //$NON-NLS-1$
+
+ private boolean activitySpecified = false;
+
+ private boolean runDefaultActivity = true;
+
+ private final String LAUNCH_DIALOG_HELP = LaunchPlugin.PLUGIN_ID + ".mainLaunchTab"; //$NON-NLS-1$
+
+ private Button defaultLauncherButton = null;
+
+ private Button vdlLauncherButton = null;
+
+ private Button deviceNameBrowseButton = null;
+
+ private final IInstanceListener instanceListener = new IInstanceListener()
+ {
+
+ private void fireUpdate()
+ {
+ Display currentDisplay = PlatformUI.getWorkbench().getDisplay();
+ if (!currentDisplay.isDisposed())
+ {
+ currentDisplay.syncExec(new Runnable()
+ {
+
+ public void run()
+ {
+ updateDeviceChooserButton();
+ updateLaunchConfigurationDialog();
+ }
+ });
+ }
+ }
+
+ public void instanceUpdated(InstanceEvent instanceevent)
+ {
+ fireUpdate();
+ }
+
+ public void instanceUnloaded(InstanceEvent instanceevent)
+ {
+ fireUpdate();
+ }
+
+ public void instanceTransitioned(InstanceEvent instanceevent)
+ {
+ fireUpdate();
+ }
+
+ public void instanceLoaded(InstanceEvent instanceevent)
+ {
+ fireUpdate();
+ }
+
+ public void instanceDeleted(InstanceEvent instanceevent)
+ {
+ fireUpdate();
+ }
+
+ public void instanceCreated(InstanceEvent instanceevent)
+ {
+ fireUpdate();
+ }
+
+ public void instanceAboutToTransition(InstanceEvent instanceevent)
+ {
+ fireUpdate();
+ }
+ };
+
+ /**
+ * @see org.eclipse.debug.ui.ILaunchConfigurationTab#createControl(org.eclipse.swt.widgets.Composite)
+ */
+ public void createControl(Composite parent)
+ {
+ Composite main = new Composite(parent, SWT.NONE);
+
+ GridLayout layout = new GridLayout(1, false);
+ GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gd.widthHint = 430;
+ gd.heightHint = 130;
+ main.setLayout(layout);
+ main.setLayoutData(gd);
+
+ createMainInfoGroup(main);
+ setControl(main);
+ }
+
+ private void updateDeviceChooserButton()
+ {
+ // button is always enabled
+ if (!deviceNameBrowseButton.isDisposed())
+ {
+ deviceNameBrowseButton.setEnabled(true);
+ }
+ }
+
+ /**
+ * Create the main information selection group
+ * @param mainComposite: the parent composite
+ */
+ private void createMainInfoGroup(Composite mainComposite)
+ {
+ this.mainComposite = mainComposite;
+
+ // create destination group
+ Group destinationGroup = new Group(mainComposite, SWT.NONE);
+ GridLayout layout = new GridLayout(3, false);
+ destinationGroup.setLayout(layout);
+ GridData defaultDestGridData = new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1);
+ destinationGroup.setLayoutData(defaultDestGridData);
+ destinationGroup.setText(LaunchNLS.LaunchComposite_UI_LaunchComposite_DestinationGroupText);
+
+ // Project Name Label
+ Label projectNameLabel = new Label(destinationGroup, SWT.NONE);
+ projectNameLabel.setText(LaunchNLS.UI_LaunchComposite_ProjectNameLabel);
+ GridData folderGridData = new GridData(SWT.LEFT, SWT.CENTER, false, false);
+ projectNameLabel.setLayoutData(folderGridData);
+
+ // Project Name Text
+ final Text projectNameText = new Text(destinationGroup, SWT.SINGLE | SWT.BORDER);
+ projectNameText.setText(projectName);
+ folderGridData = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1);
+ projectNameText.setLayoutData(folderGridData);
+ projectNameText.addModifyListener(new ModifyListener()
+ {
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.swt.events.ModifyListener#modifyText(org.eclipse.swt.events.ModifyEvent)
+ */
+ public void modifyText(ModifyEvent e)
+ {
+ if (e.data == UPDATE_WIDGETS_EVENT)
+ {
+ projectNameText.setText(projectName);
+ }
+ else
+ {
+ projectName = projectNameText.getText();
+ updateLaunchConfigurationDialog();
+ }
+ }
+ });
+
+ // Project Name Browse Button
+ Button projectNameBrowseButton = new Button(destinationGroup, SWT.PUSH);
+ folderGridData = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1);
+ projectNameBrowseButton.setLayoutData(folderGridData);
+ projectNameBrowseButton.setText(LaunchNLS.UI_LaunchComposite_BrowseButton);
+ projectNameBrowseButton.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ AndroidProjectsSelectionDialog dialog =
+ new AndroidProjectsSelectionDialog(getShell());
+ int result = dialog.open();
+ if (result == Dialog.OK)
+ {
+ Object resultProject = dialog.getFirstResult();
+ if (resultProject instanceof IProject)
+ {
+ IProject project = (IProject) resultProject;
+ projectNameText.setText(project.getName());
+ }
+ }
+ }
+
+ });
+
+ Group activityGroup = new Group(mainComposite, SWT.NONE);
+ GridLayout activityLayout = new GridLayout(3, false);
+ activityGroup.setLayout(activityLayout);
+ GridData activityGrid = new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1);
+ activityGroup.setLayoutData(activityGrid);
+ activityGroup.setText(LaunchNLS.UI_LaunchComposite_ActivityGroupLabel);
+
+ final Button defaultActivityButton = new Button(activityGroup, SWT.RADIO);
+ defaultActivityButton.setText(LaunchNLS.UI_LaunchComposite_ActivityDefaultButton);
+ GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
+ gridData.horizontalSpan = 3;
+ defaultActivityButton.setLayoutData(gridData);
+
+ // Activity Name Button
+ final Button specificActivityButton = new Button(activityGroup, SWT.RADIO);
+ specificActivityButton.setText(LaunchNLS.LaunchConfigurationTab_LaunchButton);
+ GridData activityData = new GridData(SWT.LEFT, SWT.CENTER, false, false);
+ specificActivityButton.setLayoutData(activityData);
+
+ // Activity Name Text
+ final Text activityNameText = new Text(activityGroup, SWT.SINGLE | SWT.BORDER);
+ activityNameText.setText(activityName);
+ activityData = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1);
+ activityNameText.setLayoutData(activityData);
+ activityNameText.addModifyListener(new ModifyListener()
+ {
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.swt.events.ModifyListener#modifyText(org.eclipse.swt.events.ModifyEvent)
+ */
+ public void modifyText(ModifyEvent e)
+ {
+ if (e.data == UPDATE_WIDGETS_EVENT)
+ {
+ activityNameText.setText(activityName);
+ }
+ else
+ {
+ activityName = activityNameText.getText();
+ updateLaunchConfigurationDialog();
+ }
+ }
+ });
+
+ // Activity Name Browse Button
+ final Button activityNameBrowseButton = new Button(activityGroup, SWT.PUSH);
+ activityData = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1);
+ activityNameBrowseButton.setLayoutData(activityData);
+ activityNameBrowseButton.setText(LaunchNLS.UI_LaunchComposite_BrowseButton);
+ activityNameBrowseButton.addSelectionListener(new SelectionAdapter()
+ {
+ /**
+ * Retrieve all activities of a given project
+ * @return All the activities of a given project
+ */
+ private Set<String> getAllActivities(String projectName)
+ {
+ String[] tempActivities = null;
+ Set<String> activities = new HashSet<String>();
+
+ if (projectName.length() != 0)
+ {
+ IProject selectedProject = LaunchUtils.getProject(projectName);
+
+ tempActivities = LaunchUtils.getProjectActivities(selectedProject);
+ for (String s : tempActivities)
+ {
+ activities.add(s);
+ }
+ }
+ return activities;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ if (projectName.length() == 0)
+ {
+ IWorkbenchWindow ww = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ MessageDialog.openInformation(ww.getShell(),
+ LaunchNLS.UI_LaunchComposite_ProjectRequiredTitle,
+ LaunchNLS.UI_LaunchComposite_ProjectRequiredMessage);
+ }
+ else
+ {
+
+ ElementListSelectionDialog dialog =
+ new ElementListSelectionDialog(getShell(), new LabelProvider()
+ {
+ @Override
+ public String getText(Object element)
+ {
+ String activity = (String) element;
+ return activity;
+ }
+ })
+ {
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.dialogs.ElementListSelectionDialog#createDialogArea(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ protected Control createDialogArea(Composite parent)
+ {
+ PlatformUI.getWorkbench().getHelpSystem()
+ .setHelp(parent, ACTIVITY_SELECTION_DIALOG_HELPID);
+ return super.createDialogArea(parent);
+ }
+
+ };
+
+ dialog.setTitle(LaunchNLS.UI_LaunchComposite_SelectActivityScreenTitle);
+ dialog.setMessage(LaunchNLS.UI_LaunchComposite_SelectActivityScreenMessage);
+
+ Object[] allActivities = getAllActivities(projectNameText.getText()).toArray();
+ if (allActivities.length == 0)
+ {
+ activityNameText.setText(""); //$NON-NLS-1$
+ }
+ else
+ {
+ dialog.setElements(getAllActivities(projectNameText.getText()).toArray());
+
+ int buttonId = dialog.open();
+ if (buttonId == IDialogConstants.OK_ID)
+ {
+ String activity = (String) dialog.getFirstResult();
+ activityNameText.setText(activity);
+
+ }
+ }
+ }
+ }
+
+ protected static final String ACTIVITY_SELECTION_DIALOG_HELPID =
+ "com.motorola.studio.android.launch.activitySelectionDialog"; //$NON-NLS-1$
+ });
+
+ final Button noActivityButton = new Button(activityGroup, SWT.RADIO);
+ noActivityButton.setText(LaunchNLS.LaunchConfigurationTab_DoNothingButton);
+ gridData = new GridData(GridData.FILL_HORIZONTAL);
+ gridData.horizontalSpan = 3;
+ noActivityButton.setLayoutData(gridData);
+
+ defaultActivityButton.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ if (e.data == UPDATE_WIDGETS_EVENT)
+ {
+ defaultActivityButton.setSelection(!activitySpecified && runDefaultActivity);
+ activityNameText.setEnabled(activitySpecified);
+ activityNameBrowseButton.setEnabled(activitySpecified);
+ }
+ else
+ {
+ // handle variables
+ handleActivityLauncherTypeVariables(defaultActivityButton,
+ specificActivityButton, activityNameText, activityNameBrowseButton);
+ }
+ }
+ });
+
+ specificActivityButton.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ if (e.data == UPDATE_WIDGETS_EVENT)
+ {
+ specificActivityButton.setSelection(activitySpecified && !runDefaultActivity);
+ activityNameText.setEnabled(activitySpecified);
+ activityNameBrowseButton.setEnabled(activitySpecified);
+ }
+ else
+ {
+ // handle variables
+ handleActivityLauncherTypeVariables(defaultActivityButton,
+ specificActivityButton, activityNameText, activityNameBrowseButton);
+ }
+ }
+ });
+
+ noActivityButton.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ if (e.data == UPDATE_WIDGETS_EVENT)
+ {
+ noActivityButton.setSelection(!activitySpecified && !runDefaultActivity);
+ activityNameText.setEnabled(activitySpecified);
+ activityNameBrowseButton.setEnabled(activitySpecified);
+ }
+ else
+ {
+ // handle variables
+ handleActivityLauncherTypeVariables(defaultActivityButton,
+ specificActivityButton, activityNameText, activityNameBrowseButton);
+ }
+ }
+ });
+
+ // Device Name Label
+ Label deviceNameLabel = new Label(destinationGroup, SWT.NONE);
+ deviceNameLabel.setText(LaunchNLS.UI_LaunchComposite_DeviceNameLabel);
+ GridData deviceGridData = new GridData(SWT.LEFT, SWT.CENTER, false, false);
+ deviceNameLabel.setLayoutData(deviceGridData);
+
+ // Device Name Text
+ final Text deviceNameText = new Text(destinationGroup, SWT.SINGLE | SWT.BORDER);
+ deviceNameText.setText(deviceName);
+ deviceGridData = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1);
+ deviceNameText.setLayoutData(deviceGridData);
+ deviceNameText.addModifyListener(new ModifyListener()
+ {
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.swt.events.ModifyListener#modifyText(org.eclipse.swt.events.ModifyEvent)
+ */
+ public void modifyText(ModifyEvent e)
+ {
+ if (e.data == UPDATE_WIDGETS_EVENT)
+ {
+ deviceNameText.setText(deviceName);
+ }
+ else
+ {
+ deviceName = deviceNameText.getText();
+ updateLaunchConfigurationDialog();
+ }
+ }
+ });
+
+ // Device Name Browse Button
+ deviceNameBrowseButton = new Button(destinationGroup, SWT.PUSH);
+ deviceGridData = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1);
+ deviceNameBrowseButton.setLayoutData(deviceGridData);
+ deviceNameBrowseButton.setText(LaunchNLS.UI_LaunchComposite_BrowseButton);
+ deviceNameBrowseButton.addSelectionListener(new SelectionAdapter()
+ {
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ IProject selectedProject = LaunchUtils.getProject(projectNameText.getText());
+ DeviceSelectionDialog dialog =
+ new DeviceSelectionDialog(getShell(),
+ LaunchNLS.UI_LaunchComposite_SelectDeviceScreenMessage,
+ selectedProject);
+ dialog.setTitle(LaunchNLS.UI_LaunchComposite_SelectDeviceScreenTitle);
+ dialog.setMultipleSelection(false);
+ dialog.setValidator(new ISelectionStatusValidator()
+ {
+
+ public IStatus validate(Object[] selection)
+ {
+ IStatus status = new Status(IStatus.OK, LaunchPlugin.PLUGIN_ID, ""); //$NON-NLS-1$
+ if (selection.length == 0)
+ {
+ status =
+ new Status(IStatus.ERROR, LaunchPlugin.PLUGIN_ID,
+ "No selected instance"); //$NON-NLS-1$
+ }
+ return status;
+ }
+ });
+ int res = dialog.open();
+ if (res == IDialogConstants.OK_ID)
+ {
+ ISerialNumbered serialNumbered = (ISerialNumbered) dialog.getFirstResult();
+ String selectedDevice = ((IInstance) serialNumbered).getName();
+ deviceNameText.setText(selectedDevice);
+ }
+ }
+
+ });
+
+ InstanceEventManager.getInstance().addInstanceListener(instanceListener);
+
+ Link createNewAvdLink = new Link(destinationGroup, SWT.NONE);
+ deviceGridData = new GridData(SWT.RIGHT, SWT.CENTER, true, false, 3, 1);
+ createNewAvdLink.setLayoutData(deviceGridData);
+ createNewAvdLink.setText(LaunchNLS.LaunchConfigurationTab_CreateNewAVDLink);
+ createNewAvdLink.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ OpenNewDeviceWizardHandler handler = new OpenNewDeviceWizardHandler();
+ try
+ {
+ handler.execute(new ExecutionEvent());
+ }
+ catch (ExecutionException exception)
+ {
+ //do nothing
+ }
+ }
+ });
+
+ mainComposite.addListener(SWT.Modify, new Listener()
+ {
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
+ */
+ public void handleEvent(Event e)
+ {
+ projectNameText.notifyListeners(SWT.Modify, e);
+ activityNameText.notifyListeners(SWT.Modify, e);
+ deviceNameText.notifyListeners(SWT.Modify, e);
+ defaultActivityButton.notifyListeners(SWT.Selection, e);
+ specificActivityButton.notifyListeners(SWT.Selection, e);
+ noActivityButton.notifyListeners(SWT.Selection, e);
+
+ if (defaultLauncherButton != null)
+ {
+ defaultLauncherButton.notifyListeners(SWT.Selection, e);
+ }
+ if (vdlLauncherButton != null)
+ {
+ vdlLauncherButton.notifyListeners(SWT.Selection, e);
+ }
+ }
+ });
+
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(mainComposite, LAUNCH_DIALOG_HELP); //$NON-NLS-1$
+ }
+
+ /**
+ * Handle the variables regarding Activity Launcher options.
+ *
+ * @param defaultActivityButton {@link Button} for Default Activity.
+ * @param specificActivityButton {@link Button} for Specific Activity.
+ * @param activityNameText {@link Text} holding the Activity to be launched name.
+ * @param activityNameBrowseButton Activity browser {@link Button}.
+ */
+ private void handleActivityLauncherTypeVariables(final Button defaultActivityButton,
+ final Button specificActivityButton, final Text activityNameText,
+ final Button activityNameBrowseButton)
+ {
+ activitySpecified = specificActivityButton.getSelection();
+ runDefaultActivity = defaultActivityButton.getSelection();
+ activityNameText.setEnabled(activitySpecified);
+ activityNameBrowseButton.setEnabled(activitySpecified);
+ updateLaunchConfigurationDialog();
+ }
+
+ /**
+ * @see org.eclipse.debug.ui.ILaunchConfigurationTab#getName()
+ */
+ public String getName()
+ {
+ return LaunchConfigurationTab.NAME;
+ }
+
+ /**
+ * @see org.eclipse.debug.ui.ILaunchConfigurationTab#getImage()
+ */
+ @Override
+ public Image getImage()
+ {
+ return AbstractUIPlugin.imageDescriptorFromPlugin(LaunchPlugin.PLUGIN_ID,
+ ILaunchConfigurationConstants.MOTODEV_APP_ICO).createImage();
+ }
+
+ @Override
+ public void dispose()
+ {
+ InstanceEventManager.getInstance().removeInstanceListener(instanceListener);
+ super.dispose();
+ }
+
+ /**
+ * @see org.eclipse.debug.ui.ILaunchConfigurationTab#initializeFrom(org.eclipse.debug.core.ILaunchConfiguration)
+ */
+ public void initializeFrom(ILaunchConfiguration configuration)
+ {
+ // Assure that when loading the configuration, the TmL devices are in sync with the
+ // AVD available at the SDK
+ InstancesListRefresh.refresh();
+
+ try
+ {
+ projectName =
+ configuration.getAttribute(ILaunchConfigurationConstants.ATTR_PROJECT_NAME,
+ ILaunchConfigurationConstants.DEFAULT_VALUE);
+
+ activityName =
+ configuration.getAttribute(ILaunchConfigurationConstants.ATTR_ACTIVITY,
+ ILaunchConfigurationConstants.DEFAULT_VALUE);
+
+ activitySpecified =
+ (configuration.getAttribute(ILaunchConfigurationConstants.ATTR_LAUNCH_ACTION,
+ ILaunchConfigurationConstants.ATTR_LAUNCH_ACTION_ACTIVITY)) == ILaunchConfigurationConstants.ATTR_LAUNCH_ACTION_ACTIVITY;
+
+ runDefaultActivity =
+ (configuration.getAttribute(ILaunchConfigurationConstants.ATTR_LAUNCH_ACTION,
+ ILaunchConfigurationConstants.ATTR_LAUNCH_ACTION_ACTIVITY)) == ILaunchConfigurationConstants.ATTR_LAUNCH_ACTION_DEFAULT;
+
+ deviceName =
+ configuration.getAttribute(
+ ILaunchConfigurationConstants.ATTR_DEVICE_INSTANCE_NAME,
+ ILaunchConfigurationConstants.DEFAULT_VALUE);
+
+ Event e = new Event();
+ e.type = SWT.Modify;
+ e.data = UPDATE_WIDGETS_EVENT;
+ mainComposite.notifyListeners(SWT.Modify, e);
+ }
+ catch (CoreException e)
+ {
+ // Do nothing for now
+ }
+ }
+
+ /**
+ * @see org.eclipse.debug.ui.ILaunchConfigurationTab#performApply(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy)
+ */
+ public void performApply(ILaunchConfigurationWorkingCopy configuration)
+ {
+ configuration.setAttribute(ILaunchConfigurationConstants.ATTR_PROJECT_NAME, projectName);
+ configuration.setAttribute(ILaunchConfigurationConstants.ATTR_ACTIVITY, activityName);
+
+ // For now we are not preventing the device chooser dialog to appear if the user choose a
+ // handset in the device field. However, if the user chooses an AVD, we set the preferred
+ // AVD field so that we force the launch to happen in the selected AVD without asking the
+ // user.
+ Collection<String> validAvds = SdkUtils.getAllValidVmNames();
+ if (validAvds.contains(deviceName))
+ {
+ configuration.setAttribute(ILaunchConfigurationConstants.ATTR_DEVICE_INSTANCE_NAME,
+ deviceName);
+ configuration.setAttribute(ILaunchConfigurationConstants.ATTR_ADT_DEVICE_INSTANCE_NAME,
+ deviceName);
+ }
+ else
+ {
+ configuration.setAttribute(ILaunchConfigurationConstants.ATTR_DEVICE_INSTANCE_NAME,
+ deviceName);
+ configuration
+ .removeAttribute(ILaunchConfigurationConstants.ATTR_ADT_DEVICE_INSTANCE_NAME);
+ }
+
+ if (activitySpecified)
+ {
+ configuration.setAttribute(ILaunchConfigurationConstants.ATTR_LAUNCH_ACTION,
+ ILaunchConfigurationConstants.ATTR_LAUNCH_ACTION_ACTIVITY);
+ }
+ else if (runDefaultActivity)
+ {
+ configuration.setAttribute(ILaunchConfigurationConstants.ATTR_LAUNCH_ACTION,
+ ILaunchConfigurationConstants.ATTR_LAUNCH_ACTION_DEFAULT);
+ }
+ else
+ {
+ configuration.setAttribute(ILaunchConfigurationConstants.ATTR_LAUNCH_ACTION,
+ ILaunchConfigurationConstants.ATTR_LAUNCH_ACTION_DO_NOTHING);
+ }
+
+ LaunchUtils.updateLaunchConfigurationDefaults(configuration);
+
+ IProject project = LaunchUtils.getProject(projectName);
+ IResource[] mappedResources = null;
+ if (project != null)
+ {
+ mappedResources = new IResource[]
+ {
+ project
+ };
+ }
+
+ configuration.setMappedResources(mappedResources);
+ }
+
+ /**
+ * @see org.eclipse.debug.ui.ILaunchConfigurationTab#setDefaults(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy)
+ */
+ public void setDefaults(ILaunchConfigurationWorkingCopy configuration)
+ {
+ configuration.setAttribute(ILaunchConfigurationConstants.ATTR_PROJECT_NAME,
+ ILaunchConfigurationConstants.DEFAULT_VALUE);
+ configuration.setAttribute(ILaunchConfigurationConstants.ATTR_ACTIVITY,
+ ILaunchConfigurationConstants.DEFAULT_VALUE);
+ configuration.setAttribute(ILaunchConfigurationConstants.ATTR_LAUNCH_ACTION,
+ ILaunchConfigurationConstants.ATTR_LAUNCH_ACTION_DEFAULT);
+ // It is default not to exist Preferred AVD attribute, so we just set the Studio's
+ // device instance name attribute here
+ configuration.setAttribute(ILaunchConfigurationConstants.ATTR_DEVICE_INSTANCE_NAME,
+ ILaunchConfigurationConstants.DEFAULT_VALUE);
+
+ LaunchUtils.setADTLaunchConfigurationDefaults(configuration);
+
+ projectName = ILaunchConfigurationConstants.DEFAULT_VALUE; //$NON-NLS-1$
+ activityName = ILaunchConfigurationConstants.DEFAULT_VALUE; //$NON-NLS-1$
+ deviceName = ILaunchConfigurationConstants.DEFAULT_VALUE; //$NON-NLS-1$
+ activitySpecified = ILaunchConfigurationConstants.DEFAULT_BOOL_VALUE;
+ runDefaultActivity = !ILaunchConfigurationConstants.DEFAULT_BOOL_VALUE;
+
+ if (mainComposite != null)
+ {
+ Event e = new Event();
+ e.type = SWT.Modify;
+ e.data = UPDATE_WIDGETS_EVENT;
+ mainComposite.notifyListeners(SWT.Modify, e);
+ }
+ }
+
+ /**
+ * @see ILaunchConfigurationTab#isValid(ILaunchConfiguration)
+ */
+ @Override
+ public boolean isValid(ILaunchConfiguration launchConfig)
+ {
+ boolean isValid = true;
+ boolean hasWarning = false;
+
+ String projectName = ""; //$NON-NLS-1$
+ String instanceName = ""; //$NON-NLS-1$
+ String activityName = ""; //$NON-NLS-1$
+
+ try
+ {
+ projectName =
+ launchConfig.getAttribute(ILaunchConfigurationConstants.ATTR_PROJECT_NAME,
+ ILaunchConfigurationConstants.DEFAULT_VALUE);
+ instanceName =
+ launchConfig.getAttribute(
+ ILaunchConfigurationConstants.ATTR_DEVICE_INSTANCE_NAME, (String) null);
+ activityName =
+ launchConfig.getAttribute(ILaunchConfigurationConstants.ATTR_ACTIVITY,
+ ILaunchConfigurationConstants.DEFAULT_VALUE);
+ }
+ catch (CoreException e)
+ {
+ StudioLogger.error(LaunchConfigurationTab.class,
+ "Error validating launch configuration " + launchConfig.getName(), e); //$NON-NLS-1$
+ }
+
+ /* Validate current project */
+
+ IProject project = null;
+
+ if (isValid && (projectName.length() > 0))
+ {
+ Path projectPath = new Path(projectName);
+ if (!projectPath.isValidSegment(projectName))
+ {
+ isValid = false;
+ setErrorMessage(LaunchNLS.UI_LaunchConfigurationTab_ERR_PROJECT_NOT_EXIST);
+ }
+ project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
+ if ((project != null) && !project.exists())
+ {
+ isValid = false;
+ setErrorMessage(LaunchNLS.UI_LaunchConfigurationTab_ERR_PROJECT_NOT_EXIST);
+ }
+ else if ((project != null) && SdkUtils.isLibraryProject(project))
+ {
+ isValid = false;
+ setErrorMessage(LaunchNLS.UI_LaunchConfigurationTab_ERR_PROJECT_IS_LIBRARY);
+ }
+ else if (project == null)
+ {
+ isValid = false;
+ setErrorMessage(LaunchNLS.UI_LaunchConfigurationTab_ERR_PROJECT_NOT_EXIST);
+ }
+ }
+ else if (isValid && (projectName.length() == 0))
+ {
+ setErrorMessage(null);
+ }
+
+ // if we have a chosen project, enable/disable the device selection
+ if (project != null)
+ {
+ updateDeviceChooserButton();
+ }
+
+ /* Validate current device instance */
+ if (isValid && (instanceName != null) && (instanceName.length() > 0))
+ {
+ IStatus compatible = LaunchUtils.isCompatible(project, instanceName);
+ if (compatible == null)
+ {
+ setErrorMessage(LaunchNLS.UI_LaunchConfigurationTab_ERR_DEVICE_INEXISTENT);
+ isValid = false;
+ }
+ else if (compatible.getSeverity() == IStatus.ERROR)
+ {
+ setErrorMessage(compatible.getMessage());
+ isValid = false;
+ }
+ else if (compatible.getSeverity() == IStatus.WARNING)
+ {
+ setMessage(compatible.getMessage());
+ hasWarning = true;
+ }
+ }
+ else if (isValid && (instanceName != null) && (instanceName.length() == 0))
+ {
+ setErrorMessage(null);
+ }
+
+ /* Validate current activity */
+ if (isValid && (activityName.length() > 0) && activitySpecified)
+ {
+ /*
+ * Check if the activity is valid in the current METAINF project
+ * file
+ */
+
+ Activity[] currentActivities = null;
+ boolean activityValid = false;
+
+ ManifestData manifestParser = null;
+ try
+ {
+ manifestParser = AndroidManifestParser.parse(new IFolderWrapper(project));
+ }
+ catch (Exception e)
+ {
+ StudioLogger.error(LaunchUtils.class,
+ "An error occurred trying to parse AndroidManifest", e); //$NON-NLS-1$
+ }
+ if (manifestParser != null)
+ {
+ currentActivities = manifestParser.getActivities();
+ }
+ else
+ {
+ // There's a problem with the manifest file / parser. Invalidate
+ // current settings.
+ isValid = false;
+ setErrorMessage(LaunchNLS.UI_LaunchConfigurationTab_ERR_INVALID_ACTIVITY);
+ }
+
+ /* See if the chosen activity is there */
+
+ for (Activity s : currentActivities)
+ {
+ if (s.getName().equals(activityName))
+ {
+ activityValid = true;
+ }
+ }
+
+ if (!activityValid)
+ {
+ isValid = false;
+ setErrorMessage(LaunchNLS.UI_LaunchConfigurationTab_ERR_ACTIVITY_NOT_EXIST);
+ }
+
+ }
+ else if (isValid && ((activityName.length() == 0) && activitySpecified))
+ {
+ setErrorMessage(null);
+ }
+
+ /* Wrap up validation */
+ if (isValid
+ && ((projectName.length() == 0)
+ || ((activitySpecified) && (activityName.length() == 0)) || (instanceName
+ .length() == 0)))
+ {
+ isValid = false;
+
+ if (projectName.length() == 0)
+ {
+ setMessage(LaunchNLS.UI_LaunchConfigurationTab_InfoSelectProject);
+ }
+ else if (instanceName.length() == 0)
+ {
+ setMessage(LaunchNLS.UI_LaunchConfigurationTab_InfoSelectInstance);
+ }
+ else if (activityName.length() == 0)
+ {
+ setMessage(LaunchNLS.UI_LaunchConfigurationTab_InfoSelectActivity);
+ }
+
+ }
+
+ if (isValid)
+ {
+ setErrorMessage(null);
+ if (!hasWarning)
+ {
+ setMessage(null);
+ }
+ }
+
+ return isValid;
+ }
+}
diff --git a/src/plugins/launch/src/com/motorola/studio/android/launch/ui/LaunchConfigurationTabGroup.java b/src/plugins/launch/src/com/motorola/studio/android/launch/ui/LaunchConfigurationTabGroup.java
new file mode 100644
index 0000000..4799e0e
--- /dev/null
+++ b/src/plugins/launch/src/com/motorola/studio/android/launch/ui/LaunchConfigurationTabGroup.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.motorola.studio.android.launch.ui;
+
+import org.eclipse.debug.ui.AbstractLaunchConfigurationTabGroup;
+import org.eclipse.debug.ui.CommonTab;
+import org.eclipse.debug.ui.ILaunchConfigurationDialog;
+import org.eclipse.debug.ui.ILaunchConfigurationTab;
+
+/**
+ * DESCRIPTION:
+ * This class builds the configuration tabs that are displayed when the user is
+ * editing the configuration to run MOTODEV Studio for Android applications.
+ *
+ * RESPONSIBILITY:
+ * Build the configuration tab of the "Run As" features.
+ *
+ * COLABORATORS:
+ * << class relationship>
+ *
+ * USAGE:
+ * Used only by the extension definition.
+ */
+public class LaunchConfigurationTabGroup extends AbstractLaunchConfigurationTabGroup
+{
+ /**
+ * Creates the tabs
+ *
+ * @param dialog dialog
+ * @param mode the launch mode
+ */
+ public void createTabs(ILaunchConfigurationDialog dialog, String mode)
+ {
+ ILaunchConfigurationTab mainLaunchTab = new LaunchConfigurationTab();
+ setTabs(new ILaunchConfigurationTab[]
+ {
+ mainLaunchTab, new CommonTab()
+ });
+ }
+
+}
diff --git a/src/plugins/launch/src/com/motorola/studio/android/launch/ui/StartedInstancesDialog.java b/src/plugins/launch/src/com/motorola/studio/android/launch/ui/StartedInstancesDialog.java
new file mode 100644
index 0000000..f7c03dd
--- /dev/null
+++ b/src/plugins/launch/src/com/motorola/studio/android/launch/ui/StartedInstancesDialog.java
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.motorola.studio.android.launch.ui;
+
+import java.util.Collection;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.window.ToolTip;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+import com.motorola.studio.android.AndroidPlugin;
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.emulator.core.devfrm.DeviceFrameworkManager;
+import com.motorola.studio.android.emulator.core.model.IAndroidEmulatorInstance;
+import com.motorola.studio.android.launch.ILaunchConfigurationConstants;
+import com.motorola.studio.android.launch.LaunchPlugin;
+import com.motorola.studio.android.launch.LaunchUtils;
+import com.motorola.studio.android.launch.i18n.LaunchNLS;
+
+/**
+ * This class shows a dialog to the user with online AVDs compatibles with prefferedAvd.
+ * The user can choose an online AVD and click Ok, ignore the dialog or abort the ongoing action.
+ */
+public class StartedInstancesDialog extends TitleAreaDialog
+{
+
+ Collection<IAndroidEmulatorInstance> compatibleStartedInstances = null;
+
+ private TableViewer viewer;
+
+ private IAndroidEmulatorInstance selectedInstance;
+
+ private Button okButton;
+
+ private Button ignoreButton;
+
+ private Button abortButton;
+
+ private final IAndroidEmulatorInstance preferredAvd;
+
+ private IProject project = null;
+
+ private ILaunchConfiguration configuration = null;
+
+ private boolean isUpdateConfigurationSelected = false;
+
+ private static String DIALOG_IMAGE = "icons/choose_compatible_avd_instance.png";
+
+ private static final String STARTED_INSTANCES_HELP_ID = AndroidPlugin.PLUGIN_ID
+ + ".started_instances_selection_dialog";
+
+ /**
+ * @param parentShell
+ * @throws CoreException
+ */
+ public StartedInstancesDialog(Shell parentShell,
+ Collection<IAndroidEmulatorInstance> compatibleStartedInstances,
+ ILaunchConfiguration configuration, IProject project) throws CoreException
+ {
+ super(parentShell);
+
+ this.configuration = configuration;
+ this.compatibleStartedInstances = compatibleStartedInstances;
+ this.project = project;
+
+ final String instanceName =
+ configuration.getAttribute(ILaunchConfigurationConstants.ATTR_DEVICE_INSTANCE_NAME,
+ (String) null);
+
+ this.preferredAvd = DeviceFrameworkManager.getInstance().getInstanceByName(instanceName);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.dialogs.TitleAreaDialog#createContents(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ protected Control createContents(Composite parent)
+ {
+ Control control = super.createContents(parent);
+
+ getShell().setText(LaunchNLS.UI_StartedInstancesDialog_WindowTitle);
+
+ setTitle(NLS.bind(LaunchNLS.UI_StartedInstancesDialog_Title, preferredAvd.getName()));
+ setMessage(LaunchNLS.UI_StartedInstancesDialog_Message);
+ setTitleImage(AbstractUIPlugin.imageDescriptorFromPlugin(LaunchPlugin.PLUGIN_ID,
+ DIALOG_IMAGE).createImage());
+
+ enableOkButton();
+
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, STARTED_INSTANCES_HELP_ID);
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(control, STARTED_INSTANCES_HELP_ID);
+
+ return control;
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ protected void createButtonsForButtonBar(Composite parent)
+ {
+ // create OK, Ignore and Abort buttons
+ okButton = createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
+ ignoreButton =
+ createButton(parent, IDialogConstants.IGNORE_ID, IDialogConstants.IGNORE_LABEL,
+ false);
+ abortButton =
+ createButton(parent, IDialogConstants.ABORT_ID, IDialogConstants.ABORT_LABEL, false);
+
+ ignoreButton.addMouseListener(new MouseListener()
+ {
+
+ public void mouseUp(MouseEvent e)
+ {
+ setReturnCode(IDialogConstants.IGNORE_ID);
+ close();
+ }
+
+ public void mouseDown(MouseEvent e)
+ {
+ //do nothing
+ }
+
+ public void mouseDoubleClick(MouseEvent e)
+ {
+ //do nothing
+ }
+ });
+
+ abortButton.addMouseListener(new MouseListener()
+ {
+
+ public void mouseUp(MouseEvent e)
+ {
+ setReturnCode(IDialogConstants.ABORT_ID);
+ close();
+ }
+
+ public void mouseDown(MouseEvent e)
+ {
+ //do nothing
+ }
+
+ public void mouseDoubleClick(MouseEvent e)
+ {
+ //do nothing
+ }
+ });
+ }
+
+ /**
+ * Handles the enablement of the OK button.
+ */
+ private void enableOkButton()
+ {
+ if (viewer.getTable().getSelectionCount() > 0)
+ {
+ okButton.setEnabled(true);
+ }
+ else
+ {
+ okButton.setEnabled(false);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.dialogs.TitleAreaDialog#createDialogArea(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ protected Control createDialogArea(Composite parent)
+ {
+ GridLayout layout = new GridLayout(1, false);
+ parent.setLayout(layout);
+
+ createTableArea(parent);
+
+ return parent;
+ }
+
+ /**
+ * @param parent
+ */
+ private void createTableArea(Composite parent)
+ {
+ viewer =
+ new TableViewer(parent, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL
+ | SWT.FULL_SELECTION | SWT.BORDER);
+ viewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
+ viewer.getTable().setHeaderVisible(true);
+ viewer.getTable().setLinesVisible(false);
+
+ TableViewerColumn avds = new TableViewerColumn(viewer, SWT.NONE);
+ avds.getColumn().setText(LaunchNLS.UI_StartedInstancesDialog_CompatibleAvdsColumnName);
+ avds.getColumn().setResizable(true);
+ avds.getColumn().setWidth(480);
+
+ viewer.addSelectionChangedListener(new ISelectionChangedListener()
+ {
+
+ public void selectionChanged(SelectionChangedEvent event)
+ {
+ enableOkButton();
+ }
+ });
+
+ avds.setLabelProvider(new ColumnLabelProvider()
+ {
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ColumnLabelProvider#getText(java.lang.Object)
+ */
+ @Override
+ public String getText(Object element)
+ {
+ IAndroidEmulatorInstance instance = (IAndroidEmulatorInstance) element;
+ return instance.getName() + " (" + instance.getTarget() + ", "
+ + LaunchNLS.UI_StartedInstancesDialog_ApiLevel + " "
+ + instance.getAPILevel() + ")";
+ }
+
+ @Override
+ public Image getImage(Object element)
+ {
+
+ Image img = null;
+
+ IAndroidEmulatorInstance instance = (IAndroidEmulatorInstance) element;
+ IStatus compatible = LaunchUtils.isCompatible(project, instance.getName());
+
+ // notify the warning state
+ if (compatible.getSeverity() == IStatus.WARNING)
+ {
+ img =
+ PlatformUI.getWorkbench().getSharedImages()
+ .getImage(ISharedImages.IMG_OBJS_WARN_TSK);
+ }
+
+ return img;
+ }
+
+ @Override
+ public String getToolTipText(Object element)
+ {
+ String toolTip = null;
+
+ IAndroidEmulatorInstance instance = (IAndroidEmulatorInstance) element;
+ IStatus compatible = LaunchUtils.isCompatible(project, instance.getName());
+
+ if (compatible.getSeverity() == IStatus.WARNING)
+ {
+ toolTip = LaunchNLS.UI_StartedInstancesDialog_Tooltip;
+
+ }
+
+ return toolTip;
+ }
+
+ @Override
+ public int getToolTipDisplayDelayTime(Object object)
+ {
+ return 500;
+ }
+
+ @Override
+ public int getToolTipTimeDisplayed(Object object)
+ {
+ return 5000;
+ }
+
+ });
+
+ ColumnViewerToolTipSupport.enableFor(viewer, ToolTip.NO_RECREATE);
+
+ ArrayContentProvider provider = new ArrayContentProvider();
+ viewer.setContentProvider(provider);
+ viewer.setInput(compatibleStartedInstances);
+
+ Button checkBox = new Button(parent, SWT.CHECK);
+ GridData gridData = new GridData(SWT.LEFT, SWT.CENTER, false, false);
+ checkBox.setLayoutData(gridData);
+ checkBox.setText(LaunchNLS.UI_StartedInstancesDialog_UpdateRunConfigurarion);
+ checkBox.addSelectionListener(new SelectionAdapter()
+ {
+
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ if (isUpdateConfigurationSelected)
+ {
+ isUpdateConfigurationSelected = false;
+ }
+ else
+ {
+ isUpdateConfigurationSelected = true;
+ }
+ }
+ });
+ }
+
+ public IAndroidEmulatorInstance getSelectedInstance()
+ {
+ return selectedInstance;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.dialogs.Dialog#okPressed()
+ */
+ @Override
+ protected void okPressed()
+ {
+ selectedInstance = null;
+
+ if (viewer.getTable().getSelectionCount() > 0)
+ {
+ selectedInstance =
+ (IAndroidEmulatorInstance) viewer.getTable().getSelection()[0].getData();
+ }
+
+ if (isUpdateConfigurationSelected)
+ {
+ try
+ {
+ updateRunConfiguration();
+ }
+ catch (CoreException e)
+ {
+ StudioLogger.error(StartedInstancesDialog.class,
+ "It was not possible to update the current run configuration");
+ }
+ }
+
+ super.okPressed();
+ }
+
+ private void updateRunConfiguration() throws CoreException
+ {
+ ILaunchConfigurationWorkingCopy workingCopy = configuration.getWorkingCopy();
+ workingCopy.setAttribute(ILaunchConfigurationConstants.ATTR_DEVICE_INSTANCE_NAME,
+ selectedInstance.getName());
+ workingCopy.setAttribute(ILaunchConfigurationConstants.ATTR_ADT_DEVICE_INSTANCE_NAME,
+ selectedInstance.getName());
+ workingCopy.doSave();
+ }
+}