Files
processing4/app/src/processing/mode/android/EmulatorController.java
2012-12-06 00:29:35 +00:00

176 lines
6.1 KiB
Java

package processing.mode.android;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import processing.app.Base;
import processing.app.Preferences;
import processing.app.exec.*;
import processing.core.PApplet;
class EmulatorController {
public static enum State {
NOT_RUNNING, WAITING_FOR_BOOT, RUNNING
}
private volatile State state = State.NOT_RUNNING;
public State getState() {
return state;
}
private void setState(final State state) {
if (processing.app.Base.DEBUG) {
//System.out.println("Emulator state: " + state);
new Exception("setState(" + state + ") called").printStackTrace(System.out);
}
this.state = state;
}
/**
* Blocks until emulator is running, or some catastrophe happens.
* @throws IOException
*/
synchronized public void launch() throws IOException {
if (state != State.NOT_RUNNING) {
String illegal = "You can't launch an emulator whose state is " + state;
throw new IllegalStateException(illegal);
}
String portString = Preferences.get("android.emulator.port");
if (portString == null) {
portString = "5566";
Preferences.set("android.emulator.port", portString);
}
// See http://developer.android.com/guide/developing/tools/emulator.html
final String[] cmd = new String[] {
"emulator",
"-avd", AVD.defaultAVD.name,
"-port", portString,
// "-no-boot-anim", // does this do anything?
// http://code.google.com/p/processing/issues/detail?id=1059
// "-gpu", "on" // enable OpenGL
};
//System.err.println("EmulatorController: Launching emulator");
if (Base.DEBUG) {
System.out.println(processing.core.PApplet.join(cmd, " "));
}
//ProcessResult adbResult = new ProcessHelper(adbCmd).execute();
final Process p = Runtime.getRuntime().exec(cmd);
ProcessRegistry.watch(p);
// new StreamPump(p.getInputStream(), "emulator: ").addTarget(System.out).start();
// if we've gotten this far, then we've at least succeeded in finding and
// beginning execution of the emulator, so we are now officially "Launched"
setState(State.WAITING_FOR_BOOT);
final String title = PApplet.join(cmd, ' ');
// when this shows up on stdout:
// emulator: ERROR: the cache image is used by another emulator. aborting
// need to reset adb and try again, since it's running but adb is hosed
StreamPump outie = new StreamPump(p.getInputStream(), "out: " + title);
outie.addTarget(new LineProcessor() {
public void processLine(String line) {
if (line.contains("the cache image is used by another emulator")) {
} else {
// System.out.println(line);
System.out.println(title + ": " + line);
}
}
});
//new StreamPump(p.getInputStream(), "out: " + title).addTarget(System.out).start();
// suppress this warning on OS X, otherwise we're gonna get a lot of reports:
// 2010-04-13 15:26:56.380 emulator[91699:903] Warning once: This
// application, or a library it uses, is using NSQuickDrawView, which has
// been deprecated. Apps should cease use of QuickDraw and move to Quartz.
StreamPump errie = new StreamPump(p.getErrorStream(), "err: " + title);
errie.addTarget(new LineProcessor() {
public void processLine(String line) {
if (line.contains("This application, or a library it uses, is using NSQuickDrawView")) {
// i don't really care
} else {
// System.err.println(line);
System.err.println(title + ": " + line);
}
}
});
//new StreamPump(p.getErrorStream(), "err: " + title).addTarget(System.err).start();
final CountDownLatch latch = new CountDownLatch(1);
new Thread(new Runnable() {
public void run() {
try {
//System.err.println("EmulatorController: Waiting for boot.");
while (state == State.WAITING_FOR_BOOT) {
if (processing.app.Base.DEBUG) {
System.out.println("sleeping for 2 seconds " + new java.util.Date().toString());
}
Thread.sleep(2000);
//System.out.println("done sleeping");
for (final String device : Devices.list()) {
if (device.contains("emulator")) {
//System.err.println("EmulatorController: Emulator booted.");
setState(State.RUNNING);
return;
}
}
}
System.err.println("EmulatorController: Emulator never booted. " + state);
} catch (Exception e) {
System.err.println("Exception while waiting for emulator to boot:");
e.printStackTrace();
p.destroy();
} finally {
latch.countDown();
}
}
}, "EmulatorController: Wait for emulator to boot").start();
new Thread(new Runnable() {
public void run() {
try {
final int result = p.waitFor();
// On Windows (as of SDK tools 15), emulator.exe process will terminate
// immediately, even though the emulator itself is launching correctly.
// However on OS X and Linux the process will stay open.
if (result != 0) {
System.err.println("Emulator process exited with status " + result + ".");
setState(State.NOT_RUNNING);
}
} catch (InterruptedException e) {
System.err.println("Emulator was interrupted.");
setState(State.NOT_RUNNING);
} finally {
p.destroy();
ProcessRegistry.unwatch(p);
}
}
}, "EmulatorController: emulator process waitFor()").start();
try {
latch.await();
} catch (final InterruptedException drop) {
System.err.println("Interrupted while waiting for emulator to launch.");
}
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
// whoever called them "design patterns" certainly wasn't a f*king designer.
public static EmulatorController getInstance() {
return INSTANCE;
}
private static final EmulatorController INSTANCE = new EmulatorController();
}