diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java
index ecd9236fa..2aa163c69 100644
--- a/app/src/processing/app/Base.java
+++ b/app/src/processing/app/Base.java
@@ -29,6 +29,8 @@ import java.util.*;
import javax.swing.*;
+import com.sun.codemodel.internal.JOp;
+
import processing.app.debug.Compiler;
import processing.core.*;
@@ -1672,6 +1674,127 @@ public class Base {
// ...................................................................
+
+ // incomplete
+ static public int showYesNoCancelQuestion(Editor editor, String title,
+ String primary, String secondary) {
+ if (!Base.isMacOS()) {
+ int result =
+ JOptionPane.showConfirmDialog(null, primary + "\n" + secondary, title,
+ JOptionPane.YES_NO_CANCEL_OPTION,
+ JOptionPane.QUESTION_MESSAGE);
+ return result;
+// if (result == JOptionPane.YES_OPTION) {
+//
+// } else if (result == JOptionPane.NO_OPTION) {
+// return true; // ok to continue
+//
+// } else if (result == JOptionPane.CANCEL_OPTION) {
+// return false;
+//
+// } else {
+// throw new IllegalStateException();
+// }
+
+ } else {
+ // Pane formatting adapted from the Quaqua guide
+ // http://www.randelshofer.ch/quaqua/guide/joptionpane.html
+ JOptionPane pane =
+ new JOptionPane(" " +
+ "
" +
+ "Do you want to save changes to this sketch
" +
+ " before closing?" +
+ "If you don't save, your changes will be lost.",
+ JOptionPane.QUESTION_MESSAGE);
+
+ String[] options = new String[] {
+ "Save", "Cancel", "Don't Save"
+ };
+ pane.setOptions(options);
+
+ // highlight the safest option ala apple hig
+ pane.setInitialValue(options[0]);
+
+ // on macosx, setting the destructive property places this option
+ // away from the others at the lefthand side
+ pane.putClientProperty("Quaqua.OptionPane.destructiveOption",
+ new Integer(2));
+
+ JDialog dialog = pane.createDialog(editor, null);
+ dialog.setVisible(true);
+
+ Object result = pane.getValue();
+ if (result == options[0]) {
+ return JOptionPane.YES_OPTION;
+ } else if (result == options[1]) {
+ return JOptionPane.CANCEL_OPTION;
+ } else if (result == options[2]) {
+ return JOptionPane.NO_OPTION;
+ } else {
+ return JOptionPane.CLOSED_OPTION;
+ }
+ }
+ }
+
+
+//if (result == JOptionPane.YES_OPTION) {
+ //
+// } else if (result == JOptionPane.NO_OPTION) {
+// return true; // ok to continue
+ //
+// } else if (result == JOptionPane.CANCEL_OPTION) {
+// return false;
+ //
+// } else {
+// throw new IllegalStateException();
+// }
+
+ static public int showYesNoQuestion(Editor editor, String title,
+ String primary, String secondary) {
+ if (!Base.isMacOS()) {
+ return JOptionPane.showConfirmDialog(editor,
+ primary + "\n" + secondary, title,
+ JOptionPane.YES_NO_OPTION,
+ JOptionPane.QUESTION_MESSAGE);
+ } else {
+ // Pane formatting adapted from the Quaqua guide
+ // http://www.randelshofer.ch/quaqua/guide/joptionpane.html
+ JOptionPane pane =
+ new JOptionPane(" " +
+ "
" +
+ "" + primary + "" +
+ "" + secondary + "
",
+ JOptionPane.QUESTION_MESSAGE);
+
+ String[] options = new String[] {
+ "Yes", "No"
+ };
+ pane.setOptions(options);
+
+ // highlight the safest option ala apple hig
+ pane.setInitialValue(options[0]);
+
+ JDialog dialog = pane.createDialog(editor, null);
+ dialog.setVisible(true);
+
+ Object result = pane.getValue();
+ if (result == options[0]) {
+ return JOptionPane.YES_OPTION;
+ } else if (result == options[1]) {
+ return JOptionPane.NO_OPTION;
+ } else {
+ return JOptionPane.CLOSED_OPTION;
+ }
+ }
+ }
+
+
/**
* Retrieve a path to something in the Processing folder. Eventually this
* may refer to the Contents subfolder of Processing.app, if we bundle things
diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java
index e2d972be0..c076f1870 100644
--- a/app/src/processing/app/Editor.java
+++ b/app/src/processing/app/Editor.java
@@ -1753,6 +1753,7 @@ public class Editor extends JFrame implements RunnerListener {
} else if (result == JOptionPane.CANCEL_OPTION) {
return false;
+
} else {
throw new IllegalStateException();
}
diff --git a/app/src/processing/app/tools/android/Android.java b/app/src/processing/app/tools/android/Android.java
index fd7af3e74..dfacc180f 100644
--- a/app/src/processing/app/tools/android/Android.java
+++ b/app/src/processing/app/tools/android/Android.java
@@ -23,6 +23,8 @@ package processing.app.tools.android;
import java.io.File;
import java.io.IOException;
+
+import javax.swing.JOptionPane;
//import java.util.ArrayList;
import processing.app.*;
@@ -30,8 +32,8 @@ import processing.app.tools.Tool;
import processing.core.PApplet;
-// http://dl.google.com/android/android-sdk_r3-mac.zip
// http://dl.google.com/android/repository/repository.xml
+// http://dl.google.com/android/android-sdk_r3-mac.zip
// http://dl.google.com/android/repository/tools_r03-macosx.zip
public class Android implements Tool {
@@ -44,6 +46,21 @@ public class Android implements Tool {
String emulator;
Process emulatorProcess;
+ static final String ANDROID_SDK_PRIMARY =
+ "Is the Android SDK installed?";
+ 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
" +
+ "download site at http://developer.android.com/sdk.";
+ static final String SELECT_ANDROID_SDK_FOLDER =
+ "Choose the location of the 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 =
+ "http://developer.android.com/sdk/";
+
public String getMenuTitle() {
return "Android Mode";
@@ -58,33 +75,80 @@ public class Android implements Tool {
public void run() {
editor.statusNotice("Loading Android tools.");
- checkPath();
- boolean success = Device.checkDefaults();
- if (success) {
- editor.setHandlers(new RunHandler(), new PresentHandler(),
- new StopHandler(),
- new ExportHandler(), new ExportAppHandler());
- build = new Build(editor);
- editor.statusNotice("Done loading Android tools.");
- } else {
- editor.statusError("Could not load Android tools.");
+ boolean success = checkPath();
+ if (!success) {
+ editor.statusNotice("Android mode canceled.");
+ return;
}
+ success = Device.checkDefaults();
+ if (!success) {
+ editor.statusError("Could not load Android tools.");
+ return;
+ }
+ editor.setHandlers(new RunHandler(), new PresentHandler(),
+ new StopHandler(),
+ new ExportHandler(), new ExportAppHandler());
+ build = new Build(editor);
+ editor.statusNotice("Done loading Android tools.");
}
- static protected void checkPath() {
+ protected boolean checkPath() {
Platform platform = Base.getPlatform();
- // System.out.println("PATH is " + Base.getenv("PATH"));
- // System.out.println("PATH from System is " + System.getenv("PATH"));
- if (platform.getenv("ANDROID_SDK") == null) {
- platform.setenv("ANDROID_SDK", "/opt/android");
+
+ // 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,
+ // which nukes all env variables when launching from the IDE.
+ Preferences.set("android.sdk.path", envPath);
+
+ } else {
+ sdkPath = Preferences.get("android.sdk.path");
+
+ if (sdkPath == null) {
+ int result = Base.showYesNoQuestion(editor, "Android SDK",
+ ANDROID_SDK_PRIMARY,
+ ANDROID_SDK_SECONDARY);
+ if (result == JOptionPane.YES_OPTION) {
+ File folder =
+ Base.selectFolder(SELECT_ANDROID_SDK_FOLDER, null, editor);
+ if (folder != null) {
+ boolean basicCheck = new File(folder, "tools/android").exists();
+ if (basicCheck) {
+ sdkPath = folder.getAbsolutePath();
+ Preferences.set("android.sdk.path", sdkPath);
+ } else {
+ // tools/android not found in the selected folder
+ JOptionPane.showMessageDialog(editor, NOT_ANDROID_SDK);
+ return false;
+ }
+ }
+ } else if (result == JOptionPane.NO_OPTION) {
+ // user admitted they don't have the SDK installed, and need help.
+ Base.openURL(ANDROID_SDK_URL);
+ }
+ }
}
- sdkPath = platform.getenv("ANDROID_SDK");
-// System.out.println("sdk path is " + sdkPath);
+ if (sdkPath == null) { // still not interested?
+ return false;
+ }
+ if (envPath == null) {
+ platform.setenv("ANDROID_SDK", sdkPath);
+ }
+ //platform.setenv("ANDROID_SDK", "/opt/android");
+ //sdkPath = platform.getenv("ANDROID_SDK");
+ //System.out.println("sdk path is " + sdkPath);
// sdkPath = "/opt/android";
- String toolsPath = sdkPath + File.separator + "tools";
- platform.setenv("PATH", platform.getenv("PATH") + File.pathSeparator + toolsPath);
-// System.out.println("path after set is " + Base.getenv("PATH"));
+
+ // Make sure that the tools are in the PATH
+ toolsPath = sdkPath + File.separator + "tools";
+ String path = platform.getenv("PATH");
+ platform.setenv("PATH", path + File.pathSeparator + toolsPath);
+ //System.out.println("path after set is " + Base.getenv("PATH"));
+ return true;
}
@@ -178,12 +242,12 @@ public class Android implements Tool {
return null;
}
}
-
-
+
+
public String getDefaultDevice() {
return Device.avdDonut.name;
}
-
+
/** Find connected devices */
public String findDevice() {
@@ -324,9 +388,11 @@ public class Android implements Tool {
Process p = Runtime.getRuntime().exec(new String[] {
"adb",
"-s", device,
- "shell", "am", "start",
+ //"-d", // this is for a single USB device
+ "shell", "am", "start", // kick things off
+ "-e", "debug", "true",
"-a", "android.intent.action.MAIN", "-n",
- build.getPackageName() + "/." + build.getClassName()
+ build.getPackageName() + "/." + build.getClassName()
});
int result = p.waitFor();
if (result != 0) {
diff --git a/app/src/processing/app/tools/android/Device.java b/app/src/processing/app/tools/android/Device.java
index 010aa8325..b16c2524e 100644
--- a/app/src/processing/app/tools/android/Device.java
+++ b/app/src/processing/app/tools/android/Device.java
@@ -132,10 +132,12 @@ public class Device {
protected boolean create() throws IOException {
+ // not using "-s", width + "x" + height, because that can be specified
+ // on startup, which will be easier to do for Processing apps anyway.
String[] cmd = { "android", "create", "avd",
"-n", name,
- "-t", target
-// "-s", width + "x" + height
+ "-t", target,
+ "-c", "64M"
};
//System.out.println(PApplet.join(cmd, " "));
Process p = Runtime.getRuntime().exec(cmd);