|
@@ -0,0 +1,357 @@
|
|
|
+/*
|
|
|
+ * To change this template, choose Tools | Templates
|
|
|
+ * and open the template in the editor.
|
|
|
+ */
|
|
|
+package com.jme3.gde.android;
|
|
|
+
|
|
|
+import java.io.BufferedOutputStream;
|
|
|
+import java.io.File;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.OutputStreamWriter;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.List;
|
|
|
+import org.netbeans.api.project.Project;
|
|
|
+import org.openide.DialogDisplayer;
|
|
|
+import org.openide.NotifyDescriptor;
|
|
|
+import org.openide.NotifyDescriptor.Message;
|
|
|
+import org.openide.filesystems.FileChooserBuilder;
|
|
|
+import org.openide.filesystems.FileLock;
|
|
|
+import org.openide.filesystems.FileObject;
|
|
|
+import org.openide.filesystems.FileUtil;
|
|
|
+import org.openide.util.Exceptions;
|
|
|
+import org.openide.util.NbPreferences;
|
|
|
+import org.openide.util.Utilities;
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ * @author normenhansen
|
|
|
+ */
|
|
|
+public class AndroidSdkTool {
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Starts the Android target configuration utility.
|
|
|
+ */
|
|
|
+ public static void startAndroidTool() {
|
|
|
+ startAndroidTool(false);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void startAndroidTool(boolean modal) {
|
|
|
+ final String path = getAndroidToolPath();
|
|
|
+ if (path == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Thread thread = new Thread(new Runnable() {
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ String[] command = new String[]{path};
|
|
|
+ ProcessBuilder builder = new ProcessBuilder(command);
|
|
|
+ try {
|
|
|
+ Process proc = builder.start();
|
|
|
+ OutputReader outReader = new OutputReader(proc.getInputStream());
|
|
|
+ OutputReader errReader = new OutputReader(proc.getErrorStream());
|
|
|
+ outReader.start();
|
|
|
+ errReader.start();
|
|
|
+ proc.waitFor();
|
|
|
+ } catch (InterruptedException ex) {
|
|
|
+ Exceptions.printStackTrace(ex);
|
|
|
+ } catch (IOException ex) {
|
|
|
+ Exceptions.printStackTrace(ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if (modal) {
|
|
|
+ thread.run();
|
|
|
+ } else {
|
|
|
+ thread.start();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns a FileObject for the android SDK folder, null if none is specified
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static FileObject getSdkFolder() {
|
|
|
+ String path = getSdkPath();
|
|
|
+ if (path == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ FileObject fileObj = FileUtil.toFileObject(new File(path));
|
|
|
+ if (fileObj == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return fileObj;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns a String with the path to the SDK or null if none is specified.
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static String getSdkPath() {
|
|
|
+ String path = NbPreferences.forModule(AndroidSdkTool.class).get("sdk_path", null);
|
|
|
+ if (path == null) {
|
|
|
+ FileChooserBuilder builder = new FileChooserBuilder(AndroidSdkTool.class);
|
|
|
+ builder.setTitle("Please select Android SDK Folder");
|
|
|
+ builder.setDirectoriesOnly(true);
|
|
|
+ File file = builder.showOpenDialog();
|
|
|
+ if (file != null) {
|
|
|
+ FileObject folder = FileUtil.toFileObject(file);
|
|
|
+ if (folder.getFileObject("tools") == null) {
|
|
|
+ Message msg = new NotifyDescriptor.Message(
|
|
|
+ "Not a valid SDK folder!",
|
|
|
+ NotifyDescriptor.ERROR_MESSAGE);
|
|
|
+ DialogDisplayer.getDefault().notifyLater(msg);
|
|
|
+
|
|
|
+ } else {
|
|
|
+ String name = file.getPath();
|
|
|
+ NbPreferences.forModule(AndroidSdkTool.class).put("sdk_path", name);
|
|
|
+ return name;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return path;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns a string with the path to the android tool, specific for platform (.exe for windows)
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static String getAndroidToolPath() {
|
|
|
+ FileObject executable = null;
|
|
|
+ FileObject folder = getSdkFolder();
|
|
|
+ if (folder == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ if (Utilities.isWindows()) {
|
|
|
+ executable = folder.getFileObject("tools/android.exe");
|
|
|
+ } else {
|
|
|
+ executable = folder.getFileObject("tools/android");
|
|
|
+ }
|
|
|
+ return FileUtil.toFile(executable).getPath();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Gets a list of android targets registered in the SDK
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static List<AndroidTarget> getTargetList() {
|
|
|
+ ArrayList<AndroidTarget> list = new ArrayList<AndroidTarget>();
|
|
|
+ final String path = getAndroidToolPath();
|
|
|
+ if (path == null) {
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+ String[] command = new String[]{path, "list", "targets"};
|
|
|
+ ProcessBuilder builder = new ProcessBuilder(command);
|
|
|
+ try {
|
|
|
+ Process proc = builder.start();
|
|
|
+ ListReader outReader = new ListReader(proc.getInputStream(), list);
|
|
|
+ OutputReader errReader = new OutputReader(proc.getErrorStream());
|
|
|
+ outReader.start();
|
|
|
+ errReader.start();
|
|
|
+ proc.waitFor();
|
|
|
+ } catch (InterruptedException ex) {
|
|
|
+ Exceptions.printStackTrace(ex);
|
|
|
+ } catch (IOException ex) {
|
|
|
+ Exceptions.printStackTrace(ex);
|
|
|
+ }
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+
|
|
|
+ //TODO: check mainJmeClass
|
|
|
+ public static void checkProject(Project project, String target, String name, String activity, String packag, String mainJmeClass) {
|
|
|
+ final String path = getAndroidToolPath();
|
|
|
+ if (path == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ FileObject folder = project.getProjectDirectory().getFileObject("mobile");
|
|
|
+ if (folder == null) {
|
|
|
+ try {
|
|
|
+ folder = project.getProjectDirectory().createFolder("mobile");
|
|
|
+ createProject(project, target, name, activity, packag, mainJmeClass);
|
|
|
+ } catch (IOException ex) {
|
|
|
+ Exceptions.printStackTrace(ex);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ updateProject(project, target, name);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void createProject(Project project, String target, String name, String activity, String packag, String mainJmeClass) {
|
|
|
+ final String path = getAndroidToolPath();
|
|
|
+ if (path == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ FileObject folder = project.getProjectDirectory().getFileObject("mobile");
|
|
|
+ if (folder == null) {
|
|
|
+ try {
|
|
|
+ folder = project.getProjectDirectory().createFolder("mobile");
|
|
|
+ } catch (IOException ex) {
|
|
|
+ Exceptions.printStackTrace(ex);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ String[] command = new String[]{path, "create", "project",
|
|
|
+ "--target", target,
|
|
|
+ "--name", name,
|
|
|
+ "--path", FileUtil.toFile(folder).getPath(),
|
|
|
+ "--activity", activity,
|
|
|
+ "--package", packag};
|
|
|
+ ProcessBuilder builder = new ProcessBuilder(command);
|
|
|
+ FileLock lock = null;
|
|
|
+ try {
|
|
|
+ Process proc = builder.start();
|
|
|
+ OutputReader outReader = new OutputReader(proc.getInputStream());
|
|
|
+ OutputReader errReader = new OutputReader(proc.getErrorStream());
|
|
|
+ outReader.start();
|
|
|
+ errReader.start();
|
|
|
+ proc.waitFor();
|
|
|
+ String mainActName = "mobile/src/" + packag.replaceAll("\\.", "/") + "/MainActivity.java";
|
|
|
+ FileObject mainAct = project.getProjectDirectory().getFileObject(mainActName);
|
|
|
+ if (mainAct != null) {
|
|
|
+ lock = mainAct.lock();
|
|
|
+ OutputStreamWriter out = new OutputStreamWriter(new BufferedOutputStream(mainAct.getOutputStream(lock)));
|
|
|
+ out.write(mainActivityString(mainJmeClass));
|
|
|
+ out.close();
|
|
|
+ lock.releaseLock();
|
|
|
+ } else {
|
|
|
+ throw new IOException("Cannot find " + mainAct);
|
|
|
+ }
|
|
|
+ } catch (InterruptedException ex) {
|
|
|
+ Exceptions.printStackTrace(ex);
|
|
|
+ } catch (IOException ex) {
|
|
|
+ if (lock != null) {
|
|
|
+ lock.releaseLock();
|
|
|
+ }
|
|
|
+ Exceptions.printStackTrace(ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void updateProject(Project project, String target, String name) {
|
|
|
+ final String path = getAndroidToolPath();
|
|
|
+ if (path == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ FileObject folder = project.getProjectDirectory().getFileObject("mobile");
|
|
|
+ if (folder == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ String[] command = new String[]{path, "update", "project",
|
|
|
+ "--target", target,
|
|
|
+ "--name", name,
|
|
|
+ "--path", FileUtil.toFile(folder).getPath()};
|
|
|
+ ProcessBuilder builder = new ProcessBuilder(command);
|
|
|
+ try {
|
|
|
+ Process proc = builder.start();
|
|
|
+ OutputReader outReader = new OutputReader(proc.getInputStream());
|
|
|
+ OutputReader errReader = new OutputReader(proc.getErrorStream());
|
|
|
+ outReader.start();
|
|
|
+ errReader.start();
|
|
|
+ proc.waitFor();
|
|
|
+ } catch (InterruptedException ex) {
|
|
|
+ Exceptions.printStackTrace(ex);
|
|
|
+ } catch (IOException ex) {
|
|
|
+ Exceptions.printStackTrace(ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String mainActivityString(String mainClass) {
|
|
|
+ String str = "import com.jme3.app.AndroidHarness;\n"
|
|
|
+ + "import android.content.pm.ActivityInfo;"
|
|
|
+ + "import com.jme3.system.android.AndroidConfigChooser.ConfigType;"
|
|
|
+ + "public class MainActivity extends AndroidHarness{\n"
|
|
|
+ + " public MainActivity(){\n"
|
|
|
+ + " // Set the application class to run\n"
|
|
|
+ + " appClass = \"" + mainClass + "\";\n"
|
|
|
+ + " //eglConfigType = ConfigType.FASTEST; // Default\n"
|
|
|
+ + " eglConfigType = ConfigType.BEST;\n"
|
|
|
+ + " // Exit Dialog title & message\n"
|
|
|
+ + " exitDialogTitle = \"Exit?\";\n"
|
|
|
+ + " exitDialogMessage = \"Press Yes\";\n"
|
|
|
+ + " // Edit: 25.06.2011: Enable verbose logging\n"
|
|
|
+ + " eglConfigVerboseLogging= true;\n"
|
|
|
+ + " // Edit: 30.06.2011: Choose screen orientation\n"
|
|
|
+ + " screenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;\n"
|
|
|
+ + " // Edit 12.07.2011: Invert the MouseEvents X (default = true)\n"
|
|
|
+ + " mouseEventsInvertX = true;\n"
|
|
|
+ + " // Edit 05.07.2011: Invert the MouseEvents Y (default = true)\n"
|
|
|
+ + " mouseEventsInvertY = true;\n"
|
|
|
+ + " }\n"
|
|
|
+ + "}\n";
|
|
|
+ return str;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static class AndroidTarget {
|
|
|
+
|
|
|
+ private int id;
|
|
|
+ private String name;
|
|
|
+ private String title;
|
|
|
+ private String platform;
|
|
|
+ private int apiLevel;
|
|
|
+ private int revision;
|
|
|
+ private String skins;
|
|
|
+
|
|
|
+ public int getId() {
|
|
|
+ return id;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setId(int id) {
|
|
|
+ this.id = id;
|
|
|
+ }
|
|
|
+
|
|
|
+ public String getName() {
|
|
|
+ return name;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setName(String name) {
|
|
|
+ this.name = name;
|
|
|
+ }
|
|
|
+
|
|
|
+ public String getTitle() {
|
|
|
+ return title;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setTitle(String title) {
|
|
|
+ this.title = title;
|
|
|
+ }
|
|
|
+
|
|
|
+ public String getPlatform() {
|
|
|
+ return platform;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setPlatform(String platform) {
|
|
|
+ this.platform = platform;
|
|
|
+ }
|
|
|
+
|
|
|
+ public int getApiLevel() {
|
|
|
+ return apiLevel;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setApiLevel(int apiLevel) {
|
|
|
+ this.apiLevel = apiLevel;
|
|
|
+ }
|
|
|
+
|
|
|
+ public int getRevision() {
|
|
|
+ return revision;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setRevision(int revision) {
|
|
|
+ this.revision = revision;
|
|
|
+ }
|
|
|
+
|
|
|
+ public String getSkins() {
|
|
|
+ return skins;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setSkins(String skins) {
|
|
|
+ this.skins = skins;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String toString() {
|
|
|
+ return getTitle();
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|