Skip to content

Commit

Permalink
download emulator image separately
Browse files Browse the repository at this point in the history
  • Loading branch information
codeanticode committed Jun 10, 2016
1 parent 75e8232 commit c7ad37a
Show file tree
Hide file tree
Showing 6 changed files with 511 additions and 111 deletions.
39 changes: 27 additions & 12 deletions src/processing/mode/android/AVD.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import processing.app.exec.ProcessResult;
import processing.core.PApplet;

import java.awt.Frame;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
Expand Down Expand Up @@ -74,7 +75,7 @@ public class AVD {
// static ArrayList<String> skinList;

private Map<String, String> preferredAbi = new HashMap<>(30);
private static List<String> abiList = new ArrayList<>();
private List<String> abiList = new ArrayList<>();

/** Default virtual device used by Processing. */
static public final AVD defaultAVD =
Expand All @@ -85,19 +86,15 @@ public class AVD {
public AVD(final String name, final String target) {
this.name = name;
this.target = target;

initializeAbiList();
}

private void initializeAbiList() {
if (abiList.size() == 0) {
// The order in this list determines the preference of one abi over the other
abiList.add("default/x86");
abiList.add("google_apis/x86");
abiList.add("default/x86_64");
abiList.add("google_apis/x86_64");
abiList.add("default/armeabi-v7a");
abiList.add("google_apis/armeabi-v7a");
abiList.add("default/armeabi-v7a");
}
}

Expand Down Expand Up @@ -170,9 +167,9 @@ protected boolean badness() {
return false;
}


protected boolean create(final AndroidSDK sdk) throws IOException {

protected void initTargets(final AndroidSDK sdk) throws IOException {
preferredAbi.clear();
final String[] list_abi = {
sdk.getAndroidToolPath(),
"list", "targets"
Expand Down Expand Up @@ -203,6 +200,7 @@ protected boolean create(final AndroidSDK sdk) throws IOException {

if (api != null && abis != null) {
for (String abi: abis) {
if (abiList.indexOf(abi) == -1) continue;
if (preferredAbi.get(api) == null) {
preferredAbi.put(api, abi);
} else if (abiList.indexOf(preferredAbi.get(api)) < abiList.indexOf(abi)) {
Expand Down Expand Up @@ -233,7 +231,17 @@ protected boolean create(final AndroidSDK sdk) throws IOException {
// }
// }
}
} catch (InterruptedException e) {}
} catch (InterruptedException e) {}
}

protected boolean noTargets(final AndroidSDK sdk) throws IOException {
initTargets(sdk);
return preferredAbi.size() == 0;
}


protected boolean create(final AndroidSDK sdk) throws IOException {
initTargets(sdk);

final String[] params = {
sdk.getAndroidToolPath(),
Expand All @@ -248,7 +256,7 @@ protected boolean create(final AndroidSDK sdk) throws IOException {
// Set the list to null so that exists() will check again
avdList = null;

p = new ProcessHelper(params);
ProcessHelper p = new ProcessHelper(params);
try {
// Passes 'no' to "Do you wish to create a custom hardware profile [no]"
final ProcessResult createAvdResult = p.execute("no");
Expand All @@ -270,7 +278,8 @@ protected boolean create(final AndroidSDK sdk) throws IOException {
}


static public boolean ensureProperAVD(final AndroidSDK sdk) {
static public boolean ensureProperAVD(final Frame window, final AndroidMode mode,
final AndroidSDK sdk) {
try {
if (defaultAVD.exists(sdk)) {
return true;
Expand All @@ -279,6 +288,12 @@ static public boolean ensureProperAVD(final AndroidSDK sdk) {
Messages.showWarningTiered("Android Error", AVD_LOAD_PRIMARY, AVD_LOAD_SECONDARY, null);
return false;
}
if (defaultAVD.noTargets(sdk)) {
boolean res = AndroidSDK.locateSysImage(window, mode);
if (!res) {
return false;
}
}
if (defaultAVD.create(sdk)) {
return true;
}
Expand Down
2 changes: 1 addition & 1 deletion src/processing/mode/android/AndroidEditor.java
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ public void run() {
startIndeterminate();
prepareRun();
try {
androidMode.handleRunEmulator(sketch, AndroidEditor.this);
androidMode.handleRunEmulator(sketch, AndroidEditor.this, AndroidEditor.this);
} catch (SketchException e) {
statusError(e);
} catch (IOException e) {
Expand Down
62 changes: 60 additions & 2 deletions src/processing/mode/android/AndroidMode.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,20 @@
import processing.app.ui.Editor;
import processing.app.ui.EditorException;
import processing.app.ui.EditorState;
import processing.core.PApplet;
import processing.mode.android.AndroidSDK.CancelException;
import processing.mode.java.JavaMode;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;


public class AndroidMode extends JavaMode {
Expand Down Expand Up @@ -242,15 +249,16 @@ static public String getDateStamp(long stamp) {
// runtime.launch(false);
// }
// }
public void handleRunEmulator(Sketch sketch, RunnerListener listener) throws SketchException, IOException {
public void handleRunEmulator(Sketch sketch, AndroidEditor editor,
RunnerListener listener) throws SketchException, IOException {
listener.startIndeterminate();
listener.statusNotice("Starting build...");
AndroidBuild build = new AndroidBuild(sketch, this);

listener.statusNotice("Building Android project...");
build.build("debug");

boolean avd = AVD.ensureProperAVD(sdk);
boolean avd = AVD.ensureProperAVD(editor, this, sdk);
if (!avd) {
SketchException se =
new SketchException("Could not create a virtual device for the emulator.");
Expand Down Expand Up @@ -306,6 +314,56 @@ public void handleStop(RunnerListener listener) {
}
}


public static void extractFolder(File file, File newPath, boolean setExec) throws IOException {
int BUFFER = 2048;
ZipFile zip = new ZipFile(file);
Enumeration<? extends ZipEntry> zipFileEntries = zip.entries();

// Process each entry
while (zipFileEntries.hasMoreElements()) {
// grab a zip file entry
ZipEntry entry = zipFileEntries.nextElement();
String currentEntry = entry.getName();
File destFile = new File(newPath, currentEntry);
//destFile = new File(newPath, destFile.getName());
File destinationParent = destFile.getParentFile();

// create the parent directory structure if needed
destinationParent.mkdirs();

String ext = PApplet.getExtension(currentEntry);
if (setExec && ext.equals("unknown")) {
// On some OS X machines the android binaries loose their executable
// attribute, rendering the mode unusable
destFile.setExecutable(true);
}

if (!entry.isDirectory()) {
// should preserve permissions
// https://bitbucket.org/atlassian/amps/pull-requests/21/amps-904-preserve-executable-file-status/diff
BufferedInputStream is = new BufferedInputStream(zip
.getInputStream(entry));
int currentByte;
// establish buffer for writing file
byte data[] = new byte[BUFFER];

// write the current file to disk
FileOutputStream fos = new FileOutputStream(destFile);
BufferedOutputStream dest = new BufferedOutputStream(fos,
BUFFER);

// read and write until last byte is encountered
while ((currentByte = is.read(data, 0, BUFFER)) != -1) {
dest.write(data, 0, currentByte);
}
dest.flush();
dest.close();
is.close();
}
}
zip.close();
}

// public void handleExport(Sketch sketch, )

Expand Down
77 changes: 75 additions & 2 deletions src/processing/mode/android/AndroidSDK.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,14 @@


class AndroidSDK {
static final String DOWNLOAD_URL ="https://developer.android.com/studio/index.html#downloads";

private final File folder;
private final File tools;
private final File platforms;
private final File platformTools;
private final File androidTool;

static final String DOWNLOAD_URL ="https://developer.android.com/studio/index.html#downloads";

private static final String ANDROID_SDK_PRIMARY =
"Is the Android SDK installed?";

Expand All @@ -62,6 +62,14 @@ class AndroidSDK {
"the command line tools from <a href=\"" + DOWNLOAD_URL + "\">here</a>. Make sure to install<br>" +
"the SDK platform for API 15 (Android 4.0.3) or higher.";

private static final String ANDROID_SYS_IMAGE_PRIMARY =
"Download emulator?";

private static final String ANDROID_SYS_IMAGE_SECONDARY =
"The emulator does not appear to be installed, <br>" +
"Do you want Processing to download and install it now? <br>" +
"Otherwise, you will need to do it through SDK manager.";

private static final String SELECT_ANDROID_SDK_FOLDER =
"Choose the location of the Android SDK";

Expand Down Expand Up @@ -266,6 +274,19 @@ static public AndroidSDK locate(final Frame window, final AndroidMode androidMod
}
}

static public boolean locateSysImage(final Frame window, final AndroidMode androidMode)
throws BadSDKException, CancelException, IOException {
final int result = showDownloadSysImageDialog(window);
if (result == JOptionPane.YES_OPTION) {
return downloadSysImage(window, androidMode);
} else if (result == JOptionPane.NO_OPTION) {
return false;
} else {
return false;
}
}


static public AndroidSDK download(final Frame editor, final AndroidMode androidMode)
throws BadSDKException, CancelException {
final SDKDownloader downloader = new SDKDownloader(editor, androidMode);
Expand All @@ -281,6 +302,23 @@ static public AndroidSDK download(final Frame editor, final AndroidMode androidM
return sdk;
}


static public boolean downloadSysImage(final Frame editor, final AndroidMode androidMode)
throws BadSDKException, CancelException {
final SysImageDownloader downloader = new SysImageDownloader(editor, androidMode);
downloader.run(); // This call blocks until the SDK download complete, or user cancels.

if (downloader.cancelled()) {
throw new CancelException("User canceled emulator download");
}
boolean res = downloader.getResult();
if (!res) {
throw new BadSDKException("Emulator could not be downloaded");
}
return res;
}


static public int showLocateDialog(Frame editor) {
// Pane formatting adapted from the Quaqua guide
// http://www.randelshofer.ch/quaqua/guide/joptionpane.html
Expand Down Expand Up @@ -316,7 +354,42 @@ static public int showLocateDialog(Frame editor) {
return JOptionPane.CLOSED_OPTION;
}
}

static public int showDownloadSysImageDialog(Frame editor) {
String msg1 =ANDROID_SYS_IMAGE_PRIMARY;
String msg2 = ANDROID_SYS_IMAGE_SECONDARY;

JOptionPane pane =
new JOptionPane("<html> " +
"<head> <style type=\"text/css\">"+
"b { font: 13pt \"Lucida Grande\" }"+
"p { font: 11pt \"Lucida Grande\"; margin-top: 8px; width: 300px }"+
"</style> </head>" +
"<b>" + msg1 + "</b>" +
"<p>" + msg2 + "</p>",
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.setTitle("");
dialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
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;
}
}

// this was banished from Base because it encourages bad practice.
// TODO figure out a better way to handle the above.
static public File selectFolder(String prompt, File folder, Frame frame) {
Expand Down
Loading

0 comments on commit c7ad37a

Please sign in to comment.