/* Copyright (C) 2010 Mobile Sorcery AB
This program is free software; you can redistribute it and/or modify it
under the terms of the Eclipse Public License v1.0.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the Eclipse Public License v1.0 for
more details.
You should have received a copy of the Eclipse Public License v1.0 along
with this program. It is also available at http://www.eclipse.org/legal/epl-v10.html
*/
package com.mobilesorcery.sdk.ui.targetphone.android;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Pattern;
import org.eclipse.cdt.debug.mi.core.IMILaunchConfigurationConstants;
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.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.window.IShellProvider;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.dialogs.ListDialog;
import com.mobilesorcery.sdk.builder.android.Activator;
import com.mobilesorcery.sdk.builder.android.AndroidPackager;
import com.mobilesorcery.sdk.builder.android.PropertyInitializer;
import com.mobilesorcery.sdk.builder.android.launch.ADB;
import com.mobilesorcery.sdk.builder.android.launch.AndroidNDKDebugger;
import com.mobilesorcery.sdk.builder.android.launch.ADB.ProcessKiller;
import com.mobilesorcery.sdk.builder.android.launch.AndroidEmulatorLauncher;
import com.mobilesorcery.sdk.core.AbstractTool;
import com.mobilesorcery.sdk.core.IBuildConfiguration;
import com.mobilesorcery.sdk.core.IBuildVariant;
import com.mobilesorcery.sdk.core.ILaunchConstants;
import com.mobilesorcery.sdk.core.MoSyncProject;
import com.mobilesorcery.sdk.core.MoSyncTool;
import com.mobilesorcery.sdk.core.Util;
import com.mobilesorcery.sdk.internal.launch.EmulatorLaunchConfigurationDelegate;
import com.mobilesorcery.sdk.profiles.IDeviceFilter;
import com.mobilesorcery.sdk.profiles.IProfile;
import com.mobilesorcery.sdk.profiles.ProfileDBManager;
import com.mobilesorcery.sdk.profiles.filter.AbstractDeviceFilter;
import com.mobilesorcery.sdk.ui.internal.launch.MoreLaunchShortCut;
import com.mobilesorcery.sdk.ui.targetphone.ITargetPhone;
import com.mobilesorcery.sdk.ui.targetphone.ITargetPhoneTransportDelegate;
import com.mobilesorcery.sdk.ui.targetphone.TargetPhonePlugin;
import com.mobilesorcery.sdk.ui.targetphone.TargetPhoneTransportEvent;
public class AndroidTargetPhoneTransport implements ITargetPhoneTransportDelegate {
public static final String ID = "android";
static final Pattern androidPlatformRegexp = Pattern.compile("^profiles\\\\runtimes\\\\android.*");
private static final IDeviceFilter ANDROID_DEVICE_FILTER = new AbstractDeviceFilter() {
@Override
public boolean acceptProfile(IProfile profile) {
return "android".equalsIgnoreCase(ProfileDBManager.getPlatform(profile));
}
@Override
public String getFactoryId() {
return null;
}
@Override
public void saveState(IMemento memento) {
}
};
public AndroidTargetPhoneTransport() {
}
@Override
public ITargetPhone load(IMemento memento, String name) {
String serialNo = memento.getString("serialno");
return new AndroidTargetPhone(name, serialNo, ID);
}
@Override
public boolean store(ITargetPhone phone, IMemento memento) {
if (phone instanceof AndroidTargetPhone) {
AndroidTargetPhone androidPhone = (AndroidTargetPhone) phone;
memento.putString("serialno", androidPhone.getSerialNumber());
return true;
} else {
return false;
}
}
@Override
public ITargetPhone scan(IShellProvider shellProvider, IProgressMonitor monitor) throws CoreException {
final List<String> devices = ADB.getDefault().listDeviceSerialNumbers(true);
if (devices.size() == 0) {
throw new CoreException(new Status(IStatus.ERROR, TargetPhonePlugin.PLUGIN_ID, "No android devices connected"));
}
final AndroidTargetPhone[] phone = new AndroidTargetPhone[1];
final Shell shell = shellProvider.getShell();
shell.getDisplay().syncExec(new Runnable() {
@Override
public void run() {
ListDialog dialog = new ListDialog(shell);
dialog.setTitle("Android Device");
dialog.setMessage("Select Android device to use");
dialog.setContentProvider(new ArrayContentProvider());
dialog.setLabelProvider(new LabelProvider());
dialog.setInput(devices.toArray());
if (dialog.open() == ListDialog.OK) {
Object[] dialogResult = dialog.getResult();
if (dialogResult.length > 0) {
String serialNumber = (String) dialogResult[0];
String modelName = ADB.getDefault().getModelName(serialNumber);
String name = Util.isEmpty(modelName) ? serialNumber : modelName;
phone[0] = new AndroidTargetPhone(name, serialNumber, AndroidTargetPhoneTransport.ID);
}
}
}
});
return phone[0];
}
@Override
public void send(IShellProvider shell, final MoSyncProject project, final IBuildVariant variant, ITargetPhone phone, File packageToSend, IProgressMonitor monitor)
throws CoreException {
if (phone instanceof AndroidTargetPhone) {
AndroidTargetPhone androidPhone = (AndroidTargetPhone) phone;
final String serialNumberOfDevice = androidPhone.getSerialNumber();
final String mode = project.getBuildConfiguration(variant.getConfigurationId()).getTypes().contains(IBuildConfiguration.DEBUG_TYPE) ?
"debug" : "run";
final ILaunchConfiguration[] cfg = new ILaunchConfiguration[1];
final CoreException[] exception = new CoreException[1];
shell.getShell().getDisplay().syncExec(new Runnable() {
@Override
public void run() {
try {
cfg[0] = AndroidEmulatorLauncher.findLaunchConfiguration(project, variant, mode, true, serialNumberOfDevice);
} catch (CoreException e) {
exception[0] = e;
}
}
});
if (exception[0] != null) {
throw exception[0];
}
if (cfg[0] != null) {
cfg[0].launch(mode, monitor, false);
}
} else {
throw new CoreException(new Status(IStatus.ERROR, TargetPhonePlugin.PLUGIN_ID, "Can only send to android phones"));
}
}
@Override
public String getDescription(String context) {
return "Android USB";
}
@Override
public boolean isAvailable() {
return ADB.getDefault().isValid();
}
@Override
public IDeviceFilter getAcceptedProfiles() {
return ANDROID_DEVICE_FILTER;
}
}