From bb5e072a9e02db6c30f0bdb9b9a178ffe8881e85 Mon Sep 17 00:00:00 2001 From: benfry Date: Tue, 13 Apr 2010 22:44:56 +0000 Subject: [PATCH] adding export, cleaning up --- .../app/tools/android/AndroidTool.java | 177 +++++++++++++++--- .../processing/app/tools/android/Build.java | 128 ++++++++----- .../app/tools/android/EmulatorController.java | 1 + 3 files changed, 235 insertions(+), 71 deletions(-) diff --git a/android/tool/src/processing/app/tools/android/AndroidTool.java b/android/tool/src/processing/app/tools/android/AndroidTool.java index 40b5aea6c..54f23985b 100644 --- a/android/tool/src/processing/app/tools/android/AndroidTool.java +++ b/android/tool/src/processing/app/tools/android/AndroidTool.java @@ -22,22 +22,16 @@ package processing.app.tools.android; import java.awt.Frame; -import java.io.File; +import java.io.*; import java.net.URL; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import processing.app.Base; -import processing.app.Editor; -import processing.app.Sketch; -import processing.app.debug.Runner; -import processing.app.debug.RunnerException; +import java.util.*; +import java.util.concurrent.*; +import java.util.regex.*; + +import processing.app.*; +import processing.app.debug.*; import processing.app.tools.Tool; + import processing.core.PApplet; // http://dl.google.com/android/repository/repository.xml @@ -118,17 +112,17 @@ public class AndroidTool implements Tool, DeviceListener { return true; } - public Editor getEditor() { - return editor; - } +// public Editor getEditor() { +// return editor; +// } - public Sketch getSketch() { - return editor.getSketch(); - } +// public Sketch getSketch() { +// return editor.getSketch(); +// } - public Build getBuilder() { - return build; - } +// public Build getBuilder() { +// return build; +// } // 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 @@ -165,11 +159,12 @@ public class AndroidTool implements Tool, DeviceListener { } catch (final TimeoutException expected) { } } - editor - .statusError("No, on second thought, I'm giving up on waiting for that device to show up."); + editor.statusError("No, on second thought, I'm giving up " + + "on waiting for that device to show up."); return null; } + private volatile AndroidDevice lastRunDevice = null; private void runSketchOnDevice(final Future deviceFuture) @@ -179,8 +174,8 @@ public class AndroidTool implements Tool, DeviceListener { "Building and launching...", "Creating project..."); try { - final Build build = getBuilder(); - if (!build.createProject()) { +// final Build build = getBuilder(); + if (build.createProject() != null) { return; } try { @@ -232,6 +227,119 @@ public class AndroidTool implements Tool, DeviceListener { monitor.close(); } } + + + private void buildReleaseForExport() throws Cancelled { + final IndeterminateProgressMonitor monitor = + new IndeterminateProgressMonitor(editor, + "Building and exporting...", + "Creating project..."); + try { + File tempFolder = build.createProject(); + if (tempFolder == null) { + return; + } + try { + if (monitor.isCanceled()) { + throw new Cancelled(); + } + monitor.setNote("Building release version..."); + if (!build.antBuild("release")) { + return; + } + System.out.println("build like."); + + if (monitor.isCanceled()) { + throw new Cancelled(); + } + + // If things built successfully, copy the contents to the export folder + File exportFolder = build.createExportFolder(); +// Base.openFolder(tempFolder); +// System.out.println("folder will be " + exportFolder); + if (exportFolder != null) { + Base.copyDir(tempFolder, exportFolder); + editor.statusNotice("Done with export."); + Base.openFolder(exportFolder); + } else { + System.err.println("bad copy"); + editor.statusError("Could not copy files to export folder."); + } + + } catch (IOException e) { + System.err.println("bad copy ioe"); + editor.statusError(e); + + } finally { + build.cleanup(); + } + } finally { + monitor.close(); + } + } + + + private void buildReleaseForDevice(final Future deviceFuture) throws Cancelled { + final IndeterminateProgressMonitor monitor = + new IndeterminateProgressMonitor(editor, + "Building and running...", + "Creating project..."); + try { + File tempFolder = build.createProject(); + if (tempFolder == null) { + return; + } + try { + if (monitor.isCanceled()) { + throw new Cancelled(); + } + monitor.setNote("Building..."); + if (!build.antBuild("release")) { + return; + } + + if (monitor.isCanceled()) { + throw new Cancelled(); + } + + monitor.setNote("Waiting for device to become available..."); + final AndroidDevice device = waitForDevice(deviceFuture, monitor); + if (device == null || !device.isAlive()) { + editor.statusError("Device killed or disconnected."); + return; + } + + device.addListener(this); + + if (monitor.isCanceled()) { + throw new Cancelled(); + } + monitor.setNote("Installing sketch on " + device.getId()); + if (!device.installApp(build.getPathForAPK("debug"), editor)) { + editor.statusError("Device killed or disconnected."); + return; + } + + if (monitor.isCanceled()) { + throw new Cancelled(); + } + monitor.setNote("Starting sketch on " + device.getId()); + if (startSketch(device)) { + editor.statusNotice("Sketch launched on the " + + (device.isEmulator() ? "emulator" : "phone") + "."); + } else { + editor.statusError("Could not start the sketch."); + } + + lastRunDevice = device; + } finally { + build.cleanup(); + } + } finally { + monitor.close(); + } + } + private static final Pattern LOCATION = Pattern.compile("\\(([^:]+):(\\d+)\\)"); @@ -323,9 +431,15 @@ public class AndroidTool implements Tool, DeviceListener { /** * Create a release build of the sketch and have its apk files ready. + * If users want a debug build, they can do that from the command line. */ - private static class ExportHandler implements Runnable { + private class ExportHandler implements Runnable { public void run() { + try { + buildReleaseForExport(); + } catch (final Cancelled ok) { + editor.statusNotice("Cancelled."); + } } } @@ -333,8 +447,13 @@ public class AndroidTool implements Tool, DeviceListener { * Create a release build of the sketch and install its apk files on the * attached device. */ - private static class ExportAppHandler implements Runnable { + private class ExportAppHandler implements Runnable { public void run() { + try { + buildReleaseForDevice(AndroidEnvironment.getInstance().getHardware()); + } catch (final Cancelled ok) { + editor.statusNotice("Cancelled."); + } } } diff --git a/android/tool/src/processing/app/tools/android/Build.java b/android/tool/src/processing/app/tools/android/Build.java index b110731ce..64615f3d9 100644 --- a/android/tool/src/processing/app/tools/android/Build.java +++ b/android/tool/src/processing/app/tools/android/Build.java @@ -1,27 +1,18 @@ package processing.app.tools.android; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FilenameFilter; -import java.io.IOException; -import java.io.InputStream; -import java.io.PrintStream; -import java.io.PrintWriter; +import java.io.*; import java.text.SimpleDateFormat; -import java.util.HashMap; -import java.util.List; -import org.apache.tools.ant.BuildException; -import org.apache.tools.ant.DefaultLogger; -import org.apache.tools.ant.Project; -import org.apache.tools.ant.ProjectHelper; -import processing.app.Base; -import processing.app.Editor; -import processing.app.Preferences; -import processing.app.Sketch; +import java.util.*; + +import org.apache.tools.ant.*; + +import processing.app.*; +import processing.app.exec.*; import processing.app.debug.RunnerException; import processing.app.preproc.PdePreprocessor; import processing.core.PApplet; + class Build { static SimpleDateFormat dateFormat = new SimpleDateFormat("yyMMdd.HHmm"); @@ -32,7 +23,7 @@ class Build { String className; - File androidFolder; + File tempBuildFolder; File buildFile; @@ -44,6 +35,7 @@ class Build { } // TODO this needs to be a generic function inside Sketch or elsewhere + /* protected int[] getSketchSize() { int wide = AVD.DEFAULT_WIDTH; int high = AVD.DEFAULT_HEIGHT; @@ -81,19 +73,21 @@ class Build { } return new int[] { wide, high }; } + */ - public boolean createProject() { + + public File createProject() { final Sketch sketch = editor.getSketch(); try { - androidFolder = createAndroidBuildFolder(sketch); + tempBuildFolder = createTempBuildFolder(sketch); } catch (final IOException e) { editor.statusError(e); - return false; + return null; } // Create the 'src' folder with the preprocessed code. - final File srcFolder = new File(androidFolder, "src"); + final File srcFolder = new File(tempBuildFolder, "src"); try { final File javaFolder = mkdirs(srcFolder, getPackageName().replace('.', @@ -111,17 +105,17 @@ class Build { sketch.prepare(); className = sketch.preprocess(buildPath, new Preproc(sketch.getName())); if (className != null) { - final File androidXML = new File(androidFolder, "AndroidManifest.xml"); + final File androidXML = new File(tempBuildFolder, "AndroidManifest.xml"); writeAndroidManifest(androidXML, sketch.getName(), className); - writeBuildProps(new File(androidFolder, "build.properties")); - buildFile = new File(androidFolder, "build.xml"); + writeBuildProps(new File(tempBuildFolder, "build.properties")); + buildFile = new File(tempBuildFolder, "build.xml"); writeBuildXML(buildFile, sketch.getName()); - writeDefaultProps(new File(androidFolder, "default.properties")); - writeLocalProps(new File(androidFolder, "local.properties")); - writeRes(new File(androidFolder, "res"), className); + writeDefaultProps(new File(tempBuildFolder, "default.properties")); + writeLocalProps(new File(tempBuildFolder, "local.properties")); + writeRes(new File(tempBuildFolder, "res"), className); - final File libsFolder = mkdirs(androidFolder, "libs"); - final File assetsFolder = mkdirs(androidFolder, "assets"); + final File libsFolder = mkdirs(tempBuildFolder, "libs"); + final File assetsFolder = mkdirs(tempBuildFolder, "assets"); final InputStream input = PApplet.createInput(AndroidTool .getCoreZipFile()); @@ -144,18 +138,19 @@ class Build { } } catch (final RunnerException e) { editor.statusError(e); - return false; + return null; } catch (final IOException e) { editor.statusError(e); - return false; + return null; } - return true; + return tempBuildFolder; } /** * The Android dex util pukes on paths containing spaces, which will happen * most of the time on Windows, since Processing sketches wind up in * "My Documents". Therefore, build android in a temp file. + * http://code.google.com/p/android/issues/detail?id=4567 * * TODO: better would be to retrieve the 8.3 name for the sketch folder! * @@ -163,7 +158,7 @@ class Build { * @return A folder in which to build the android sketch * @throws IOException */ - private File createAndroidBuildFolder(final Sketch sketch) throws IOException { + private File createTempBuildFolder(final Sketch sketch) throws IOException { final File tmp = File.createTempFile("android", ".pde"); if (!(tmp.delete() && tmp.mkdir())) { throw new IOException("Cannot create temp dir " + tmp @@ -171,15 +166,64 @@ class Build { } return tmp; } + + + protected File createExportFolder() throws IOException { + Sketch sketch = editor.getSketch(); + // Create the 'android' build folder, and move any existing version out. + File androidFolder = new File(sketch.getFolder(), "android"); + if (androidFolder.exists()) { + Date mod = new Date(androidFolder.lastModified()); + File dest = new File(sketch.getFolder(), "android." + dateFormat.format(mod)); + boolean result = androidFolder.renameTo(dest); + if (!result) { + ProcessHelper mv; + ProcessResult pr; + try { + System.err.println("createProject renameTo() failed, resorting to mv/move instead."); + mv = new ProcessHelper("mv", androidFolder.getAbsolutePath(), dest.getAbsolutePath()); + pr = mv.execute(); + + } catch (IOException e) { + editor.statusError(e); + return null; + + } catch (InterruptedException e) { + e.printStackTrace(); + return null; + } + if (!pr.succeeded()) { + System.err.println(pr.getStderr()); + Base.showWarning("Failed to rename", + "Could not rename the old “android” build folder.\n" + + "Please delete, close, or rename the folder\n" + + androidFolder.getAbsolutePath() + "\n" + + "and try again." , null); + Base.openFolder(sketch.getFolder()); + return null; + } + } + } else { + boolean result = androidFolder.mkdirs(); + if (!result) { + Base.showWarning("Folders, folders, folders", + "Could not create the necessary folders to build.\n" + + "Perhaps you have some file permissions to sort out?", null); + return null; + } + } + return androidFolder; + } + + /** - * @param target - * "debug" or "release" + * @param target "debug" or "release" */ boolean antBuild(final String target) { final Project p = new Project(); - p.setUserProperty("ant.file", buildFile.getAbsolutePath() - .replace('\\', '/')); + String path = buildFile.getAbsolutePath().replace('\\', '/'); + p.setUserProperty("ant.file", path); // deals with a problem where javac error messages weren't coming through p.setUserProperty("build.compiler", "extJavac"); @@ -319,7 +363,7 @@ class Build { String getPathForAPK(final String target) { final Sketch sketch = editor.getSketch(); - final File apkFile = new File(androidFolder, "bin/" + sketch.getName() + final File apkFile = new File(tempBuildFolder, "bin/" + sketch.getName() + "-" + target + ".apk"); return apkFile.getAbsolutePath(); } @@ -365,8 +409,8 @@ class Build { //"java.util.zip.*", "java.util.regex.*" // not necessary w/ newer i/o }; - Preferences.set("android.preproc.imports.list", PApplet.join( - androidImports, ",")); + Preferences.set("android.preproc.imports.list", + PApplet.join(androidImports, ",")); return androidImports; } @@ -606,7 +650,7 @@ class Build { } public void cleanup() { - rm(androidFolder); + rm(tempBuildFolder); } private void rm(final File f) { diff --git a/android/tool/src/processing/app/tools/android/EmulatorController.java b/android/tool/src/processing/app/tools/android/EmulatorController.java index 9c064d0f7..2f0e8f72a 100644 --- a/android/tool/src/processing/app/tools/android/EmulatorController.java +++ b/android/tool/src/processing/app/tools/android/EmulatorController.java @@ -58,6 +58,7 @@ class EmulatorController { // beginning execution of the emulator, so we are now officially "Launched" setState(State.WAITING_FOR_BOOT); + // TODO need to suppress this warning on OS X // 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.