package com.gorillalogic.monkeyconsole.emulator;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
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.jface.action.Action;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.console.ConsolePlugin;
import org.eclipse.ui.console.IConsole;
import org.eclipse.ui.console.IConsoleManager;
import org.eclipse.ui.console.IOConsole;
import org.eclipse.ui.console.IOConsoleOutputStream;
import com.gorillalogic.monkeytalk.utils.FileUtils;
public class StartEmulatorAction extends Action {
protected static String STARTEMULATOR_ERROR_TITLE = "Start Emulator Error";
protected static String DEFAULT_EMULATOR_PATH = ".monkeytalk/MonkeyTalkDemoEmulator";
protected static String DEFAULT_EMULATOR_MARKER = "MonkeyTalkDemoEmulator.avd";
protected static String DEFAULT_EMULATOR_EXECUTABLE_CONTAINING_DIR = "MonkeyTalkDemoEmulator.avd";
protected static String EMULATOR_EXECUTABLE_MAC="emulator";
protected static String EMULATOR_EXECUTABLE_WIN="emulator.exe";
protected static String LATEST_EMULATOR_DOWNLOAD_URL="http://www.gorillalogic.com/sites/default/files/MonkeyTalkDemoEmulator.zip";
Shell shell;
PrintStream consoleStream = null;
protected static Process theEmulatorProcess = null;
public StartEmulatorAction(Shell shell) {
this.shell = shell;
}
public void run() {
File emulatorMarker = null;
try {
emulatorMarker=checkForEmulator();
if (emulatorMarker!=null) {
// the thing is already downloaded
URL newerVersion=checkForNewerVersion(emulatorMarker);
if (newerVersion!=null) {
if (askToDownload(true)) {
downloadEmulator(newerVersion); // starts Job
return;
}
}
} else {
// they don't have the emulator yet
if (askToDownload(false)) {
downloadEmulator(getLatestVersion()); // starts job
}
return;
}
runStartEmulator();
} catch (Exception e) {
MessageBox dialog = getMessageBox(SWT.ICON_ERROR | SWT.OK);
dialog.setText(STARTEMULATOR_ERROR_TITLE);
String exceptionMessage = e.getMessage();
if (exceptionMessage==null) {
exceptionMessage = "an unknown error occurred: " + e.getClass().getName();
}
dialog.setMessage(exceptionMessage);
dialog.open();
return;
}
}
protected void runStartEmulator() throws IOException {
if (theEmulatorProcess!=null) {
MessageBox dialog = getMessageBox(SWT.ICON_ERROR | SWT.OK);
dialog.setText(STARTEMULATOR_ERROR_TITLE);
dialog.setMessage("Emulator is already runing.");
dialog.open();
return;
}
File emulatorMarker=checkForEmulator();
if (emulatorMarker==null) {
throw new IOException("Could not locate builtin emulator!");
}
// get the job parameters
//StartEmulatorDialog dialog = new StartEmulatorDialog(getDialogParent(), null);
//dialog.create();
//if (dialog.open() != Window.OK) {
// they cancelled
// return;
//}
// if the current file is a script, generate a suite for it
//final File selectedApk = dialog.getSelectedApk();
final File selectedApk = null;;
Job job = new StartEmulatorJob(this.getDefaultEmulatorDir(), selectedApk);
job.setUser(true);
job.schedule();
}
private MessageBox getMessageBox(int flags) {
MessageBox dialog = new MessageBox(getDialogParent(), flags);
return dialog;
}
private Shell getDialogParent() {
return shell;
}
private class StartEmulatorJob extends Job {
File selectedApk;
File emulatorDir;
public StartEmulatorJob(File emulatorDir, File selectedApk) {
super("Starting Emulator" + (selectedApk==null ? "" : (": " + selectedApk.getName())) );
this.selectedApk = selectedApk;
this.emulatorDir = emulatorDir;
}
@Override
protected IStatus run(IProgressMonitor arg0) {
arg0.beginTask(this.getName(), IProgressMonitor.UNKNOWN);
// launch the emulator
int style;
String message;
IStatus status;
try {
theEmulatorProcess = startEmulator(selectedApk);
if (theEmulatorProcess==null) {
style=SWT.ICON_ERROR | SWT.OK;
message="Emulator failed to start!";
status=Status.CANCEL_STATUS;
} else {
style=SWT.ICON_INFORMATION | SWT.OK;
message="Emulator started!";
status=Status.OK_STATUS;
}
} catch (Exception e) {
style = SWT.ICON_ERROR | SWT.OK;
message="Error Starting Emulator " + (selectedApk==null ? "" : (": " + selectedApk.getName()))
+ "\n" + e.getMessage();
status=Status.CANCEL_STATUS;
}
final int _style=style;
final String _message=message;
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
MessageBox dialog2 = getMessageBox(_style);
dialog2.setText("Emulator Startup");
dialog2.setMessage(_message);
dialog2.open();
}
});
return status;
}
protected Process startEmulator(File selectedApk) throws IOException {
String executableName;
File workingDirectory = new File(emulatorDir,DEFAULT_EMULATOR_EXECUTABLE_CONTAINING_DIR);
if (isWindows()) {
executableName=workingDirectory.getAbsolutePath() + File.separator + EMULATOR_EXECUTABLE_WIN;
} else {
executableName = "." + File.separator + EMULATOR_EXECUTABLE_MAC;
}
/*
String emulatorExecutable = new File(workingDirectory,DEFAULT_EMULATOR_EXECUTABLE).getAbsolutePath();
String sysdir = emulatorDir.getAbsolutePath();
String system = new File(emulatorDir,"system.img").getAbsolutePath();
String kernel = new File(emulatorDir,"kernel-qemu").getAbsolutePath();
String partitionSize = "218";
String ramdisk = new File(emulatorDir,"ramdisk.img").getAbsolutePath();
String skindir = emulatorDir.getAbsolutePath();
String skin = "WVGA800";
String datadir = emulatorDir.getAbsolutePath();
*/
String emulatorExecutable = executableName;
String sysdir = "." + File.separator;
String system = "system.img";
String kernel = "kernel-qemu";
String partitionSize = "218";
String ramdisk = "ramdisk.img";
String skindir = "." + File.separator;
String skin = "WVGA800";
String datadir = "." + File.separator;
ArrayList<String> commands = new ArrayList<String>();
commands.add(emulatorExecutable);
commands.add("-sysdir");
commands.add(sysdir);
commands.add("-system");
commands.add(system);
commands.add("-kernel");
commands.add(kernel);
commands.add("-partition-size");
commands.add(partitionSize);
commands.add("-ramdisk");
commands.add(ramdisk);
commands.add("-skindir");
commands.add(skindir);
commands.add("-skin");
commands.add(skin);
commands.add("-datadir");
commands.add(datadir);
return runEmulator(workingDirectory, commands);
}
}
private Process runEmulator(File workingDirectory, List<String> commands) throws IOException {
ProcessBuilder pb = new ProcessBuilder();
pb.directory(workingDirectory);
pb.redirectErrorStream(true);
pb.command(commands);
Process p=pb.start();
if (p!=null) {
sendOutputToConsole(p);
}
return p;
}
protected void sendOutputToConsole(Process p) {
final Process pp=p;
new Thread(
new Runnable() {
@Override
public void run() {
PrintStream consoleStream = getConsolePrintStream("MonkeyTalk Android Emulator");
try {
BufferedInputStream processOutput = new BufferedInputStream(pp.getInputStream());
int i;
while ((i=processOutput.read())!=-1) {
consoleStream.print((char)i);
}
theEmulatorProcess=null;
} catch(Exception e) {
consoleStream.println("Error reading output of MonkeyTalk emulator:" + e.getMessage());
} finally {
if (theEmulatorProcess!=null) {
consoleStream.println("Emulator exited abnormally!");
try {
theEmulatorProcess.destroy();
} catch (Exception e) {
// do nothing
}
theEmulatorProcess=null;
}
consoleStream.close();
}
}
}
).start();
}
protected File checkForEmulator() {
File emulatorMarkerFile = new File(getDefaultEmulatorDir(), DEFAULT_EMULATOR_MARKER);
if (emulatorMarkerFile.exists()) {
return emulatorMarkerFile;
}
return null;
}
protected File getDefaultEmulatorDir() {
String[] folders = DEFAULT_EMULATOR_PATH.split("/");
File defaultEmulatorDir = new File(System.getProperty("user.home"));
for (String folder : folders) {
defaultEmulatorDir = new File(defaultEmulatorDir, folder);
}
return defaultEmulatorDir;
}
private PrintStream getConsolePrintStream() {
return getConsolePrintStream(null);
}
private PrintStream getConsolePrintStream(String title) {
if (consoleStream == null) {
IOConsole console = new IOConsole(title!=null?title:"", null);
console.setConsoleWidth(80);
IConsoleManager manager = ConsolePlugin.getDefault().getConsoleManager();
IConsole[] existing = manager.getConsoles();
boolean exists = false;
for (int i = 0; i < existing.length; i++ ) {
if(console == existing[i]) {
exists = true;
}
}
if(!exists) {
manager.addConsoles(new IConsole[] {console});
}
manager.showConsoleView(console);
IOConsoleOutputStream stream = console.newOutputStream();
consoleStream = new PrintStream(stream);
}
return consoleStream;
}
private URL getLatestVersion() throws MalformedURLException {
return checkForNewerVersion(null);
}
private URL checkForNewerVersion(File marker) throws MalformedURLException {
if (marker==null) {
return new URL(LATEST_EMULATOR_DOWNLOAD_URL);
}
return null;
}
private boolean askToDownload(boolean newer) {
MessageBox dialog = getMessageBox(SWT.ICON_INFORMATION | SWT.OK | SWT.CANCEL);
dialog.setText("Download MonkeyTalk Android Emulator");
String message;
if (newer) {
message = "A newer version of the MonkeyTalk Android Emulator is available.\nDownload it now?";
} else {
message = "The MonkeyTalk Android Emulator is not installed.\nDownload it now?";
}
dialog.setMessage(message);
int result = dialog.open();
return (result == SWT.OK);
}
private void downloadEmulator(URL url) throws IOException {
File downloadDir = this.getDefaultEmulatorDir().getParentFile();
File zipfile = new File(downloadDir,"MonkeyTalkDemoEmulator_download.zip");
DownloadEmulatorJob job = new DownloadEmulatorJob(url, zipfile);
job.setUser(true);
job.schedule();
}
private class DownloadEmulatorJob extends Job {
URL url;
File downloadTarget;
public DownloadEmulatorJob(URL url, File downloadTarget) {
super("Downloading MonkeyTalk Demo Emulator");
this.url = url;
this.downloadTarget = downloadTarget;
}
@Override
protected IStatus run(IProgressMonitor arg0) {
try {
File downloadDir = downloadTarget.getParentFile();
downloadDir.mkdirs();
org.apache.commons.io.FileUtils.copyURLToFile(url, downloadTarget);
com.gorillalogic.monkeytalk.utils.FileUtils.unzipFile(downloadTarget, downloadDir);
} catch (Exception e) {
final Exception ee = e;
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
MessageBox dialog2 = getMessageBox(SWT.ICON_ERROR | SWT.OK);
dialog2.setText("Emulator Download Error");
dialog2.setMessage(ee.getMessage());
dialog2.open();
}
});
return Status.CANCEL_STATUS;
}
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
try {
runStartEmulator();
} catch (Exception e) {
MessageBox dialog2 = getMessageBox(SWT.ICON_ERROR | SWT.OK);
dialog2.setText("Emulator Startup Error");
dialog2.setMessage(e.getMessage());
dialog2.open();
}
}
});
return Status.OK_STATUS;
}
}
protected boolean isWindows() {
return System.getProperty("os.name").toLowerCase().contains("win");
}
}