/* * 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; } }