diff --git a/android/todo.txt b/android/todo.txt index 421c136e5..b178fb947 100644 --- a/android/todo.txt +++ b/android/todo.txt @@ -1,4 +1,5 @@ 0175 (private) +X fix problem with windows claiming "does not appear to contain an Android SDK" P1 this is embarrassing, need to fix ASAP diff --git a/app/src/processing/app/tools/android/Android.java b/app/src/processing/app/tools/android/Android.java index febfbc998..192d93689 100644 --- a/app/src/processing/app/tools/android/Android.java +++ b/app/src/processing/app/tools/android/Android.java @@ -43,25 +43,25 @@ public class Android implements Tool { private Editor editor; Build build; - + String emulator; Process emulatorProcess; - static final String ANDROID_SDK_PRIMARY = + static final String ANDROID_SDK_PRIMARY = "Is the Android SDK installed?"; - static final String ANDROID_SDK_SECONDARY = + static final String ANDROID_SDK_SECONDARY = "The Android SDK does not appear to be installed,
" + "because the ANDROID_SDK variable is not set.
" + "If it is installed, click “Yes” to select the
" + - "location of the SDK, or “No” to visit the SDK
" + + "location of the SDK, or “No” to visit the SDK
" + "download site at http://developer.android.com/sdk."; - static final String SELECT_ANDROID_SDK_FOLDER = + static final String SELECT_ANDROID_SDK_FOLDER = "Choose the location of the Android SDK"; - static final String NOT_ANDROID_SDK = + static final String NOT_ANDROID_SDK = "The selected folder does not appear to contain an Android SDK."; - static final String ANDROID_SDK_URL = + static final String ANDROID_SDK_URL = "http://developer.android.com/sdk/"; - + static final String ADB_SOCKET_PORT = "29892"; static final String ANDROID_CORE_URL = @@ -69,7 +69,7 @@ public class Android implements Tool { static final String ANDROID_CORE_FILENAME = "processing-android-core.zip"; - + public String getMenuTitle() { return "Android Mode"; } @@ -83,7 +83,7 @@ public class Android implements Tool { public void run() { // System.out.println("being called like so:"); // new Exception().printStackTrace(); - + editor.statusNotice("Loading Android tools."); boolean success = checkPath(); @@ -94,33 +94,33 @@ public class Android implements Tool { // Make sure things are going to behave properly. checkServer(); - + success = Device.checkDefaults(); if (!success) { editor.statusError("Could not load Android tools."); return; } - + // Make sure that the processing.android.core.* classes are available checkCore(); - - editor.setHandlers(new RunHandler(), new PresentHandler(), + + editor.setHandlers(new RunHandler(), new PresentHandler(), new StopHandler(), new ExportHandler(), new ExportAppHandler()); build = new Build(editor); editor.statusNotice("Done loading Android tools."); } - + protected boolean checkPath() { Platform platform = Base.getPlatform(); - + // The environment variable is king. The preferences.txt entry is a page. String envPath = platform.getenv("ANDROID_SDK"); if (envPath != null) { sdkPath = envPath; - // Just set the pref, in case it the ANDROID_SDK variable gets - // knocked out later. For instance, by that pesky Eclipse, + // Just set the pref, in case it the ANDROID_SDK variable gets + // knocked out later. For instance, by that pesky Eclipse, // which nukes all env variables when launching from the IDE. Preferences.set("android.sdk.path", envPath); @@ -128,17 +128,19 @@ public class Android implements Tool { sdkPath = Preferences.get("android.sdk.path"); if (sdkPath == null) { - int result = Base.showYesNoQuestion(editor, "Android SDK", + int result = Base.showYesNoQuestion(editor, "Android SDK", ANDROID_SDK_PRIMARY, ANDROID_SDK_SECONDARY); if (result == JOptionPane.YES_OPTION) { - File folder = + File folder = Base.selectFolder(SELECT_ANDROID_SDK_FOLDER, null, editor); if (folder != null) { - boolean basicCheck = new File(folder, "tools/android").exists(); + boolean basicCheck = Base.isWindows() ? + new File(folder, "tools/android.exe").exists() : + new File(folder, "tools/android").exists(); if (basicCheck) { sdkPath = folder.getAbsolutePath(); - Preferences.set("android.sdk.path", sdkPath); + Preferences.set("android.sdk.path", sdkPath); } else { // tools/android not found in the selected folder JOptionPane.showMessageDialog(editor, NOT_ANDROID_SDK); @@ -172,13 +174,13 @@ public class Android implements Tool { /** - * And by "check" server, I mean kill it and start it again. For now, the + * And by "check" server, I mean kill it and start it again. For now, the * debug bridge seems to get into a bad state frequently, and it's not clear * how to properly query whether that's the case. *

* On second thought, that's been scratched because the forced start/stop * seems to cause even more instability. - */ + */ protected boolean checkServer() { // when "adb get-state" returns "unknown", that means that the SocketAttach // will probably fail, however it happily returns "device" in other cases @@ -219,8 +221,8 @@ public class Android implements Tool { // otherwise do the usual return new File(Base.getSketchbookFolder(), ANDROID_CORE_FILENAME); } - - + + protected boolean checkCore() { //File target = new File(Base.getSketchbookFolder(), ANDROID_CORE_FILENAME); File target = getCoreZipFile(); @@ -229,7 +231,7 @@ public class Android implements Tool { URL url = new URL(ANDROID_CORE_URL); PApplet.saveStream(target, url.openStream()); } catch (Exception e) { - Base.showWarning("Download Error", + Base.showWarning("Download Error", "Could not download Android core.zip", e); return false; } @@ -239,18 +241,18 @@ public class Android implements Tool { /** - * The debug bridge seems to get into a bad state frequently, and it's not - * clear how to properly query whether that's the case. + * The debug bridge seems to get into a bad state frequently, and it's not + * clear how to properly query whether that's the case. *

- * For instance, when loading the Android tools and checking installed - * AVDs, the check will commonly return no entries, even though the + * For instance, when loading the Android tools and checking installed + * AVDs, the check will commonly return no entries, even though the * defaults have been created. Then the code tries to create the AVDs * again, only to return an error. *

- * In other cases, launching connector.attach() from AndroidRunner will - * simply hang, rather than returning an error or (ever) timing out. + * In other cases, launching connector.attach() from AndroidRunner will + * simply hang, rather than returning an error or (ever) timing out. * (Even if the timeout arg is set for SocketAttach.) There doesn't seem to - * be a good way to query whether this is going to happen before it happens. + * be a good way to query whether this is going to happen before it happens. */ static protected boolean resetServer(Editor editor) { try { @@ -258,7 +260,7 @@ public class Android implements Tool { // don't really care about this result... killer.waitFor(); killer.printLines(); - + Thread.sleep(1000); // just take a quick break so that the server can die // ...we only care about whether it was able to start successfully. @@ -267,14 +269,14 @@ public class Android implements Tool { starter.printLines(); if (result == 0) { return true; - } + } killer.printLines(); // okay maybe now we care about these starter.printLines(); // something to confuse the user a bit - editor.statusError("Could not start Android debug server."); + editor.statusError("Could not start Android debug server."); } catch (IOException e) { editor.statusError(e); - + } catch (InterruptedException e) { e.printStackTrace(); } @@ -285,8 +287,8 @@ public class Android implements Tool { public Editor getEditor() { return editor; } - - + + public Sketch getSketch() { return editor.getSketch(); } @@ -295,8 +297,8 @@ public class Android implements Tool { public Build getBuilder() { return build; } - - + + /** * Launch an emulator if not already running. * @return The name of the emulator. @@ -314,7 +316,7 @@ public class Android implements Tool { // not done yet, let's continue } } - + String portString = Preferences.get("android.emulator.port"); if (portString == null) { portString = "5566"; @@ -322,12 +324,12 @@ public class Android implements Tool { } //int port = Integer.parseInt(portString); String name = "emulator-" + portString; - + if (emulatorProcess != null) { // this must be it, if we're running System.out.println("Found a perfectly good emulator. Trying that."); return name; } - + try { String[] devices = Device.list(); for (String s : devices) { @@ -340,23 +342,23 @@ public class Android implements Tool { editor.statusError(e); return null; } - + //# starts and uses port 5554 for communication (but not logs) //emulator -avd gee1 -port 5554 //# only informative messages and up (emulator -help-logcat for more info) //emulator -avd gee1 -logcat '*:i' //# faster boot - //emulator -avd gee1 -logcat '*:i' -no-boot-anim + //emulator -avd gee1 -logcat '*:i' -no-boot-anim //# only get System.out and System.err - //emulator -avd gee1 -logcat 'System.*:i' -no-boot-anim + //emulator -avd gee1 -logcat 'System.*:i' -no-boot-anim //# though lots of messages aren't through System.*, so that's not great //# need to instead use the adb interface - + // launch emulator because it's not running yet try { editor.statusNotice("Starting new Android emulator."); - String[] cmd = new String[] { - "emulator", + String[] cmd = new String[] { + "emulator", "-avd", getDefaultDevice(), "-port", portString, //"-logcat", "'*:i'", @@ -366,12 +368,12 @@ public class Android implements Tool { System.out.println(PApplet.join(cmd, " ")); // "emulator: ERROR: the user data image is used by another emulator. aborting" // make sure that the streams are drained properly - new StreamRedirectThread("android-emulator-out", + new StreamRedirectThread("android-emulator-out", emulatorProcess.getInputStream(), System.out).start(); - new StreamRedirectThread("android-emulator-err", + new StreamRedirectThread("android-emulator-err", emulatorProcess.getErrorStream(), System.err).start(); return name; - + } catch (IOException e) { //e.printStackTrace(); editor.statusError(e); @@ -406,16 +408,16 @@ public class Android implements Tool { } return null; } - - + + //adb -s emulator-5556 install helloWorld.apk -//: adb -s HT91MLC00031 install bin/Brightness-debug.apk +//: adb -s HT91MLC00031 install bin/Brightness-debug.apk //532 KB/s (190588 bytes in 0.349s) // pkg: /data/local/tmp/Brightness-debug.apk //Failure [INSTALL_FAILED_ALREADY_EXISTS] -//: adb -s HT91MLC00031 install -r bin/Brightness-debug.apk +//: adb -s HT91MLC00031 install -r bin/Brightness-debug.apk //1151 KB/s (190588 bytes in 0.161s) // pkg: /data/local/tmp/Brightness-debug.apk //Success @@ -424,10 +426,10 @@ public class Android implements Tool { // if user asks for 480x320, 320x480, 854x480 etc, then launch like that // though would need to query the emulator to see if it can do that - + public void installAndRun(String target, String device) { boolean success; - + // //adb get-state // try { // System.out.print("(installAndRun) adb get state: "); @@ -441,7 +443,7 @@ public class Android implements Tool { // Simply reset the debug bridge, since it seems so prone to getting // into bad states and not producing error messages. //resetServer(); - + Build build = getBuilder(); success = build.createProject(); if (!success) return; @@ -474,18 +476,18 @@ public class Android implements Tool { success = waitUntilReady(device); if (!success) return; - + success = installSketch(device); if (!success) return; // Returns the last JDWP port that in use before launching String prevPort = startSketch(device); if (prevPort == null) return; - + success = debugSketch(device, prevPort); } - - + + protected boolean waitUntilReady(String device) { long timeout = System.currentTimeMillis() + 30 * 1000; // 15 sec @@ -516,7 +518,7 @@ public class Android implements Tool { if (result == 0) return true; // error.finish(); // output.finish(); - + p.printLines(); /* // for (String err : error.getLines()) { @@ -532,7 +534,7 @@ public class Android implements Tool { } } */ - + try { Thread.sleep(1000); } catch (InterruptedException ie) { } @@ -584,13 +586,13 @@ public class Android implements Tool { // //System.out.println("last is " + last); // return last.trim(); for (int i = lines.length-1; i >= 0; --i) { - String s = lines[i].trim(); + String s = lines[i].trim(); if (s.length() != 0) { return s; } } return null; - + } else { for (String err : p.getErrorLines()) { if (err.length() != 0) { @@ -598,7 +600,7 @@ public class Android implements Tool { } } } - + try { Thread.sleep(1000); } catch (InterruptedException ie) { } @@ -608,19 +610,19 @@ public class Android implements Tool { } return null; } - - + + boolean installSketch(String device) { // install the new package into the emulator //System.out.println("installing onto emulator/device"); boolean emu = device.startsWith("emulator"); - editor.statusNotice("Sending sketch to the " + + editor.statusNotice("Sending sketch to the " + (emu ? "emulator" : "phone") + "."); try { // Device.sendMenuButton(device); // wake up // Device.sendHomeButton(device); // kill any running app - - String[] cmd = new String[] { + + String[] cmd = new String[] { "adb", "-s", device, //"wait-for-device", @@ -628,7 +630,7 @@ public class Android implements Tool { build.getPathForAPK("debug") }; Process p = Runtime.getRuntime().exec(cmd); - + System.out.println(); System.out.print("Install command: "); System.out.println(PApplet.join(cmd, " ")); @@ -646,7 +648,7 @@ public class Android implements Tool { editor.statusError("Could not install the sketch."); System.out.println("“adb install” returned " + result + "."); return false; - + } else { String errorMsg = null; for (String out : output.getLines()) { @@ -674,9 +676,9 @@ public class Android implements Tool { editor.statusError(e); } catch (InterruptedException e) { } - + return false; - } + } // better version that actually runs through JDI: @@ -685,14 +687,14 @@ public class Android implements Tool { try { // Device.sendMenuButton(device); // wake up // Device.sendHomeButton(device); // kill any running app - + String lastPort = getJdwpPort(device); - + //"am start -a android.intent.action.MAIN -n com.android.browser/.BrowserActivity" - Process p = Runtime.getRuntime().exec(new String[] { + Process p = Runtime.getRuntime().exec(new String[] { "adb", "-s", device, - //"-d", // this is for a single USB device + //"-d", // this is for a single USB device "shell", "am", "start", // kick things off // -D causes a hang with "waiting for the debugger to attach" // "-D", // debug @@ -705,12 +707,12 @@ public class Android implements Tool { if (result != 0) { editor.statusError("Could not start the sketch."); System.err.println("“adb shell” for “am start” returned " + result + "."); - + } else { boolean emu = device.startsWith("emulator"); - editor.statusNotice("Sketch started on the " + + editor.statusNotice("Sketch started on the " + (emu ? "emulator" : "phone") + "."); - + return lastPort; } } catch (IOException e) { @@ -720,9 +722,9 @@ public class Android implements Tool { } return null; } - - - + + + boolean debugSketch(String device, String prevPort) { try { String port = null; @@ -730,7 +732,7 @@ public class Android implements Tool { //while (port == null || port.equals(prevPort)) { while (System.currentTimeMillis() < timeout) { if (port != null) { - System.out.println("Waiting a half second " + + System.out.println("Waiting a half second " + "for the application to launch..."); try { Thread.sleep(500); @@ -738,7 +740,7 @@ public class Android implements Tool { } port = getJdwpPort(device); if (!port.equals(prevPort)) { -// System.out.println("I'm digging port " + port + +// System.out.println("I'm digging port " + port + // " instead of " + prevPort + "."); break; } @@ -746,7 +748,7 @@ public class Android implements Tool { System.out.println("Found application on port " + port + "."); // Originally based on helpful notes by Agus Santoso (http://j.mp/7zV69M) - + // adb -s emulator-5566 jdwp // prints a list of connections that can be made to the device // the final port will be the entry of the most recently started application @@ -758,7 +760,7 @@ public class Android implements Tool { String[] cmd = new String[] { "adb", "-s", device, - "forward", + "forward", "tcp:" + ADB_SOCKET_PORT, "jdwp:" + port }; @@ -792,8 +794,8 @@ public class Android implements Tool { return false; } - - + + /** * Build the sketch and run it inside an emulator with the debugger. */ @@ -803,7 +805,7 @@ public class Android implements Tool { checkServer(); String device = findEmulator(); boolean success; - + Build build = getBuilder(); success = build.createProject(); if (!success) return; @@ -824,23 +826,23 @@ public class Android implements Tool { if (prevPort == null) return; success = debugSketch(device, prevPort); - } + } } - - + + /** * Build the sketch and run it on a device with the debugger connected. */ class PresentHandler implements Runnable { public void run() { - checkServer(); + checkServer(); String device = findDevice(); if (device == null) { editor.statusError("No device found."); } else { //installAndRun("debug", device); boolean success; - + Build build = getBuilder(); success = build.createProject(); if (!success) return; @@ -865,17 +867,17 @@ public class Android implements Tool { } } - + class StopHandler implements Runnable { public void run() { } } - - + + /** - * Create a release build of the sketch and have its apk files ready. + * Create a release build of the sketch and have its apk files ready. */ - class ExportHandler implements Runnable { + class ExportHandler implements Runnable { public void run() { } } @@ -883,10 +885,10 @@ public class Android implements Tool { /** * Create a release build of the sketch and install its apk files on the - * attached device. + * attached device. */ - class ExportAppHandler implements Runnable { - public void run() { + class ExportAppHandler implements Runnable { + public void run() { } } } \ No newline at end of file diff --git a/todo.txt b/todo.txt index ee97d288a..db23c917f 100644 --- a/todo.txt +++ b/todo.txt @@ -1,5 +1,6 @@ 0175 pde (private) +_ "not a valid android install" msg on windows (not checking .exe) _ move build scripts to something better like ant _ too much to maintain the multiple versions, too much code