Browse Source

- add android deployment to SDK

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@8190 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
nor..67 14 years ago
parent
commit
a09c8f8446
27 changed files with 1775 additions and 2 deletions
  1. 1 1
      build.xml
  2. 8 0
      jme3-android/build.xml
  3. 6 0
      jme3-android/manifest.mf
  4. 45 0
      jme3-android/nbproject/build-impl.xml
  5. 8 0
      jme3-android/nbproject/genfiles.properties
  6. 89 0
      jme3-android/nbproject/platform.properties
  7. 5 0
      jme3-android/nbproject/project.properties
  8. 143 0
      jme3-android/nbproject/project.xml
  9. 1 0
      jme3-android/nbproject/suite.properties
  10. BIN
      jme3-android/release/libs/jMonkeyEngine3-android.jar
  11. 357 0
      jme3-android/src/com/jme3/gde/android/AndroidSdkTool.java
  12. 12 0
      jme3-android/src/com/jme3/gde/android/Bundle.properties
  13. 84 0
      jme3-android/src/com/jme3/gde/android/ImportantFilesNode.java
  14. 81 0
      jme3-android/src/com/jme3/gde/android/ListReader.java
  15. 133 0
      jme3-android/src/com/jme3/gde/android/MobileCompositeProvider.java
  16. 149 0
      jme3-android/src/com/jme3/gde/android/MobileCustomizerPanel.form
  17. 183 0
      jme3-android/src/com/jme3/gde/android/MobileCustomizerPanel.java
  18. 61 0
      jme3-android/src/com/jme3/gde/android/OutputReader.java
  19. 21 0
      jme3-android/src/com/jme3/gde/android/jme3-android.xml
  20. 26 0
      jme3-android/src/com/jme3/gde/android/layer.xml
  21. 38 0
      jme3-android/src/com/jme3/gde/android/mobile-targets.xml
  22. 6 0
      jme3-android/src/com/jme3/gde/android/properties/Bundle.properties
  23. 76 0
      jme3-android/src/com/jme3/gde/android/properties/MobileOptionsPanelController.java
  24. 87 0
      jme3-android/src/com/jme3/gde/android/properties/MobilePanel.form
  25. 153 0
      jme3-android/src/com/jme3/gde/android/properties/MobilePanel.java
  26. BIN
      jme3-android/src/com/jme3/gde/android/properties/Phone_16.gif
  27. 2 1
      nbproject/project.properties

+ 1 - 1
build.xml

@@ -96,7 +96,7 @@
       -->
       
     <!--creates update center version via hudson build server-->
-    <target name="hudson-nightly" depends="suite.clean, update-help-sets, -revert-svn-changes, set-impl-version, suite.nbms, unset-impl-version">
+    <target name="hudson-nightly" depends="suite.clean, -revert-svn-changes, update-help-sets, set-impl-version, suite.nbms, unset-impl-version">
     </target>
 
     <target name="hudson-stable" depends="suite.clean, -revert-svn-changes, set-impl-version, suite.nbms, unset-impl-version">

+ 8 - 0
jme3-android/build.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- You may freely edit this file. See harness/README in the NetBeans platform -->
+<!-- for some information on what you could do (e.g. targets to override). -->
+<!-- If you delete this file and reopen the project it will be recreated. -->
+<project name="com.jme3.gde.android" default="netbeans" basedir=".">
+    <description>Builds, tests, and runs the project com.jme3.gde.android.</description>
+    <import file="nbproject/build-impl.xml"/>
+</project>

+ 6 - 0
jme3-android/manifest.mf

@@ -0,0 +1,6 @@
+Manifest-Version: 1.0
+OpenIDE-Module: com.jme3.gde.android
+OpenIDE-Module-Implementation-Version: 0
+OpenIDE-Module-Layer: com/jme3/gde/android/layer.xml
+OpenIDE-Module-Localizing-Bundle: com/jme3/gde/android/Bundle.properties
+

+ 45 - 0
jme3-android/nbproject/build-impl.xml

@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+*** GENERATED FROM project.xml - DO NOT EDIT  ***
+***         EDIT ../build.xml INSTEAD         ***
+-->
+<project name="com.jme3.gde.android-impl" basedir="..">
+    <fail message="Please build using Ant 1.7.1 or higher.">
+        <condition>
+            <not>
+                <antversion atleast="1.7.1"/>
+            </not>
+        </condition>
+    </fail>
+    <property file="nbproject/private/suite-private.properties"/>
+    <property file="nbproject/suite.properties"/>
+    <fail unless="suite.dir">You must set 'suite.dir' to point to your containing module suite</fail>
+    <property file="${suite.dir}/nbproject/private/platform-private.properties"/>
+    <property file="${suite.dir}/nbproject/platform.properties"/>
+    <macrodef name="property" uri="http://www.netbeans.org/ns/nb-module-project/2">
+        <attribute name="name"/>
+        <attribute name="value"/>
+        <sequential>
+            <property name="@{name}" value="${@{value}}"/>
+        </sequential>
+    </macrodef>
+    <macrodef name="evalprops" uri="http://www.netbeans.org/ns/nb-module-project/2">
+        <attribute name="property"/>
+        <attribute name="value"/>
+        <sequential>
+            <property name="@{property}" value="@{value}"/>
+        </sequential>
+    </macrodef>
+    <property file="${user.properties.file}"/>
+    <nbmproject2:property name="harness.dir" value="nbplatform.${nbplatform.active}.harness.dir" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
+    <nbmproject2:property name="nbplatform.active.dir" value="nbplatform.${nbplatform.active}.netbeans.dest.dir" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
+    <nbmproject2:evalprops property="cluster.path.evaluated" value="${cluster.path}" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
+    <fail message="Path to 'platform' cluster missing in $${cluster.path} property or using corrupt Netbeans Platform (missing harness).">
+        <condition>
+            <not>
+                <contains string="${cluster.path.evaluated}" substring="platform"/>
+            </not>
+        </condition>
+    </fail>
+    <import file="${harness.dir}/build.xml"/>
+</project>

+ 8 - 0
jme3-android/nbproject/genfiles.properties

@@ -0,0 +1,8 @@
+build.xml.data.CRC32=018d14a3
+build.xml.script.CRC32=6461359b
[email protected]
+# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
+# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
+nbproject/build-impl.xml.data.CRC32=018d14a3
+nbproject/build-impl.xml.script.CRC32=abd1e01a
+nbproject/[email protected]

+ 89 - 0
jme3-android/nbproject/platform.properties

@@ -0,0 +1,89 @@
+cluster.path=\
+    ${nbplatform.active.dir}/extra:\
+    ${nbplatform.active.dir}/harness:\
+    ${nbplatform.active.dir}/ide:\
+    ${nbplatform.active.dir}/java:\
+    ${nbplatform.active.dir}/platform
+disabled.modules=\
+    org.netbeans.libs.bugtracking,\
+    org.netbeans.libs.bugzilla,\
+    org.netbeans.libs.jsr223,\
+    org.netbeans.libs.smack,\
+    org.netbeans.libs.springframework,\
+    org.netbeans.libs.swingx,\
+    org.netbeans.modules.apisupport.apidocs,\
+    org.netbeans.modules.bugtracking,\
+    org.netbeans.modules.bugtracking.bridge,\
+    org.netbeans.modules.bugzilla,\
+    org.netbeans.modules.db,\
+    org.netbeans.modules.db.core,\
+    org.netbeans.modules.db.dataview,\
+    org.netbeans.modules.db.drivers,\
+    org.netbeans.modules.db.kit,\
+    org.netbeans.modules.db.metadata.model,\
+    org.netbeans.modules.db.mysql,\
+    org.netbeans.modules.db.sql.editor,\
+    org.netbeans.modules.db.sql.visualeditor,\
+    org.netbeans.modules.dbapi,\
+    org.netbeans.modules.dbschema,\
+    org.netbeans.modules.derby,\
+    org.netbeans.modules.form,\
+    org.netbeans.modules.form.binding,\
+    org.netbeans.modules.form.j2ee,\
+    org.netbeans.modules.form.kit,\
+    org.netbeans.modules.form.nb,\
+    org.netbeans.modules.form.refactoring,\
+    org.netbeans.modules.glassfish.common,\
+    org.netbeans.modules.hibernate,\
+    org.netbeans.modules.hibernatelib,\
+    org.netbeans.modules.hudson,\
+    org.netbeans.modules.hudson.ant,\
+    org.netbeans.modules.hudson.git,\
+    org.netbeans.modules.hudson.maven,\
+    org.netbeans.modules.hudson.mercurial,\
+    org.netbeans.modules.hudson.subversion,\
+    org.netbeans.modules.hudson.tasklist,\
+    org.netbeans.modules.i18n.form,\
+    org.netbeans.modules.j2ee.core.utilities,\
+    org.netbeans.modules.j2ee.jpa.refactoring,\
+    org.netbeans.modules.j2ee.jpa.verification,\
+    org.netbeans.modules.j2ee.persistence,\
+    org.netbeans.modules.j2ee.persistence.kit,\
+    org.netbeans.modules.j2ee.toplinklib,\
+    org.netbeans.modules.jellytools,\
+    org.netbeans.modules.jellytools.ide,\
+    org.netbeans.modules.jellytools.java,\
+    org.netbeans.modules.jellytools.platform,\
+    org.netbeans.modules.jemmy,\
+    org.netbeans.modules.languages,\
+    org.netbeans.modules.maven,\
+    org.netbeans.modules.maven.checkstyle,\
+    org.netbeans.modules.maven.coverage,\
+    org.netbeans.modules.maven.embedder,\
+    org.netbeans.modules.maven.grammar,\
+    org.netbeans.modules.maven.graph,\
+    org.netbeans.modules.maven.hints,\
+    org.netbeans.modules.maven.indexer,\
+    org.netbeans.modules.maven.junit,\
+    org.netbeans.modules.maven.kit,\
+    org.netbeans.modules.maven.model,\
+    org.netbeans.modules.maven.osgi,\
+    org.netbeans.modules.maven.persistence,\
+    org.netbeans.modules.maven.refactoring,\
+    org.netbeans.modules.maven.repository,\
+    org.netbeans.modules.maven.search,\
+    org.netbeans.modules.maven.spring,\
+    org.netbeans.modules.server,\
+    org.netbeans.modules.spellchecker,\
+    org.netbeans.modules.spellchecker.bindings.htmlxml,\
+    org.netbeans.modules.spellchecker.bindings.properties,\
+    org.netbeans.modules.spellchecker.dictionary_en,\
+    org.netbeans.modules.spellchecker.kit,\
+    org.netbeans.modules.spring.beans,\
+    org.netbeans.modules.websvc.saas.codegen.java,\
+    org.netbeans.modules.xml.wsdl.model,\
+    org.openide.compat,\
+    org.openide.options,\
+    org.openide.util.enumerations
+nbjdk.active=default
+nbplatform.active=default

+ 5 - 0
jme3-android/nbproject/project.properties

@@ -0,0 +1,5 @@
+#Updated by build script
+#Thu, 25 Aug 2011 21:00:54 +0200
+javac.source=1.6
+javac.compilerargs=-Xlint -Xlint\:-serial
+spec.version.base=3.0.0

+ 143 - 0
jme3-android/nbproject/project.xml

@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://www.netbeans.org/ns/project/1">
+    <type>org.netbeans.modules.apisupport.project</type>
+    <configuration>
+        <data xmlns="http://www.netbeans.org/ns/nb-module-project/3">
+            <code-name-base>com.jme3.gde.android</code-name-base>
+            <suite-component/>
+            <module-dependencies>
+                <dependency>
+                    <code-name-base>com.jme3.gde.core</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <specification-version>3.0</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.netbeans.api.progress</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <specification-version>1.24</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.netbeans.modules.java.j2seproject</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <implementation-version/>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.netbeans.modules.java.project</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <specification-version>1.29.1</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.netbeans.modules.options.api</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <specification-version>1.22</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.netbeans.modules.project.ant</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <specification-version>1.37</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.netbeans.modules.projectapi</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <specification-version>1.20</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.netbeans.modules.projectuiapi</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <specification-version>1.30</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.awt</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>7.31</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.dialogs</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>7.10</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.filesystems</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>7.20</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.loaders</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>7.21</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.nodes</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>7.21</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.util</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>8.0</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.util.lookup</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>8.8</specification-version>
+                    </run-dependency>
+                </dependency>
+            </module-dependencies>
+            <public-packages>
+                <package>com.jme3.gde.android</package>
+            </public-packages>
+        </data>
+    </configuration>
+</project>

+ 1 - 0
jme3-android/nbproject/suite.properties

@@ -0,0 +1 @@
+suite.dir=${basedir}/..

BIN
jme3-android/release/libs/jMonkeyEngine3-android.jar


+ 357 - 0
jme3-android/src/com/jme3/gde/android/AndroidSdkTool.java

@@ -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();
+        }
+    }
+}

+ 12 - 0
jme3-android/src/com/jme3/gde/android/Bundle.properties

@@ -0,0 +1,12 @@
+jme3-android=jme3-android
+OpenIDE-Module-Display-Category=jMonkeyEngine
+OpenIDE-Module-Name=Android Support
+OpenIDE-Module-Short-Description=Provides Android deployment for jMonkeyEngine SDK
+LBL_Category_Mobile=Mobile
+MobileCustomizerPanel.jLabel2.text=Mobile Deployment
+MobileCustomizerPanel.jCheckBox1.text=Enable Android Deployment
+MobileCustomizerPanel.jLabel1.text=Android Target
+MobileCustomizerPanel.jLabel3.text=Application Package
+MobileCustomizerPanel.jTextField1.text=jTextField1
+MobileCustomizerPanel.jButton2.text=Run Android Target Configuration Utility
+MobileCustomizerPanel.jTextArea1.text=Tip:\nTo recreate the android build project, uncheck the checkbox and press OK, then open this window again and re-enable the checkbox.

+ 84 - 0
jme3-android/src/com/jme3/gde/android/ImportantFilesNode.java

@@ -0,0 +1,84 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.gde.android;
+
+import org.netbeans.api.project.Project;
+import org.netbeans.spi.project.LookupProvider;
+import org.netbeans.spi.project.ui.support.NodeFactory;
+import org.netbeans.spi.project.ui.support.NodeFactorySupport;
+import org.netbeans.spi.project.ui.support.NodeList;
+import org.openide.filesystems.FileObject;
+import org.openide.loaders.DataObject;
+import org.openide.loaders.DataObjectNotFoundException;
+import org.openide.nodes.FilterNode;
+import org.openide.nodes.Node;
+import org.openide.util.Exceptions;
+import org.openide.util.Lookup;
+import org.openide.util.lookup.Lookups;
+
+/**
+ *
+ * @author normenhansen
+ */
+public class ImportantFilesNode extends FilterNode {
+
+    public ImportantFilesNode(Project proj) throws DataObjectNotFoundException {
+//        super(DataObject.find(proj.getProjectDirectory().getFileObject("mobile/AndroidManifest.xml")).getNodeDelegate());
+        super(Node.EMPTY);
+    }
+
+    @Override
+    public String getDisplayName() {
+        return "Android Manifest";
+    }
+
+    public static class LookupProviderImpl implements LookupProvider {
+
+        public Lookup createAdditionalLookup(Lookup lookup) {
+
+            Project prj = lookup.lookup(Project.class);
+
+            //create node if lookup has important files node
+            FileObject folder = prj.getProjectDirectory().getFileObject("mobile");
+            if (folder != null && folder.isFolder()) {
+                return Lookups.fixed(new ImportantFilesLookupItem(prj));
+            }
+
+            return Lookups.fixed();
+
+        }
+    }
+
+    public static class ImportantFilesNodeFactoryImpl implements NodeFactory {
+
+        public NodeList createNodes(Project project) {
+
+//        this.proj = project;
+
+            //If our item is in the project's lookup,
+            //return a new node in the node list:
+            ImportantFilesLookupItem item = project.getLookup().lookup(ImportantFilesLookupItem.class);
+            if (item != null) {
+                try {
+                    ImportantFilesNode nd = new ImportantFilesNode(project);
+                    return NodeFactorySupport.fixedNodeList(nd);
+                } catch (DataObjectNotFoundException ex) {
+                    Exceptions.printStackTrace(ex);
+                }
+            }
+
+            //If our item isn't in the lookup,
+            //then return an empty list of nodes:
+            return NodeFactorySupport.fixedNodeList();
+
+        }
+    }
+
+    public static class ImportantFilesLookupItem {
+
+        public ImportantFilesLookupItem(Project prj) {
+        }
+    }
+}

+ 81 - 0
jme3-android/src/com/jme3/gde/android/ListReader.java

@@ -0,0 +1,81 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.gde.android;
+
+import com.jme3.gde.android.AndroidSdkTool.AndroidTarget;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.netbeans.api.progress.ProgressHandle;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author normenhansen
+ */
+public class ListReader implements Runnable {
+
+    private Thread thread;
+    private BufferedReader in;
+    private ProgressHandle progress;
+    private ArrayList<AndroidTarget> list;
+
+    public ListReader(InputStream in, ArrayList<AndroidTarget> list) {
+        this.in = new BufferedReader(new InputStreamReader(in));
+        this.list = list;
+    }
+
+    public ListReader(BufferedReader in, ArrayList<AndroidTarget> list) {
+        this.in = in;
+        this.list = list;
+    }
+
+    public void start() {
+        thread = new Thread(this);
+        thread.start();
+    }
+
+    public void run() {
+        try {
+            String line;
+            AndroidTarget target = null;
+            while ((line = in.readLine()) != null) {
+                line = line.trim();
+                if (line.length() > 0) {
+                    if (line.startsWith("id:")) {
+                        target = new AndroidTarget();
+                        int idstart = line.indexOf(":") + 1;
+                        int idend = line.indexOf("or");
+                        int start = line.indexOf("\"") + 1;
+                        int end = line.lastIndexOf("\"");
+                        target.setId(Integer.parseInt(line.substring(idstart, idend).trim()));
+                        target.setName(line.substring(start, end));
+                        list.add(target);
+                    }
+                    if (line.startsWith("Name:") && target != null) {
+                        target.setTitle(line.split(":")[1].trim());
+                    }
+                    if (progress != null) {
+                        progress.progress(line);
+                    } else {
+                        Logger.getLogger(this.getClass().getName()).log(Level.INFO, line);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            Exceptions.printStackTrace(e);
+        }
+    }
+
+    /**
+     * @param progress the progress to set
+     */
+    public void setProgress(ProgressHandle progress) {
+        this.progress = progress;
+    }
+}

+ 133 - 0
jme3-android/src/com/jme3/gde/android/MobileCompositeProvider.java

@@ -0,0 +1,133 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.gde.android;
+
+import com.jme3.gde.core.j2seproject.ProjectExtensionManager;
+import com.jme3.gde.core.j2seproject.ProjectExtensionProperties;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import javax.swing.JComponent;
+
+import org.netbeans.api.project.Project;
+import org.netbeans.spi.project.ui.support.ProjectCustomizer;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+
+import org.openide.util.Exceptions;
+import org.openide.util.Lookup;
+import org.openide.util.NbBundle;
+
+/**
+ *
+ * @author normenhansen
+ */
[email protected](projectType = "org-netbeans-modules-java-j2seproject", category = "Application", position = 400)
+public class MobileCompositeProvider implements ProjectCustomizer.CompositeCategoryProvider {
+
+    private static final String CAT_MOBILE = "MobileDeployment"; // NOI18N
+    private static ProjectExtensionProperties jwsProps = null;
+    private String[] keyList = new String[]{
+        "application.title",
+        "main.class",
+        "mobile.android.enabled",
+        "mobile.android.package",
+        "mobile.android.target"
+    };
+
+    public MobileCompositeProvider() {
+    }
+
+    @Override
+    public ProjectCustomizer.Category createCategory(Lookup context) {
+        return ProjectCustomizer.Category.create(CAT_MOBILE,
+                NbBundle.getMessage(MobileCompositeProvider.class, "LBL_Category_Mobile"), null);
+    }
+
+    @Override
+    public JComponent createComponent(ProjectCustomizer.Category category, Lookup context) {
+        jwsProps = new ProjectExtensionProperties(context.lookup(Project.class), keyList);
+        MobileCustomizerPanel panel = new MobileCustomizerPanel(jwsProps);
+        category.setStoreListener(new SavePropsListener(jwsProps, context.lookup(Project.class)));
+        category.setOkButtonListener(panel);
+        return panel;
+    }
+
+    private class SavePropsListener implements ActionListener {
+
+        private String extensionName = "mobile";
+        private String extensionVersion = "v0.9";
+        private String[] extensionDependencies = new String[]{"jar", "-mobile-deployment"};
+        private ProjectExtensionManager manager = new ProjectExtensionManager(extensionName, extensionVersion, extensionDependencies);
+        private ProjectExtensionProperties properties;
+        private Project project;
+
+        public SavePropsListener(ProjectExtensionProperties props, Project project) {
+            this.properties = props;
+            this.project = project;
+            manager.setAntTaskLibrary("jme3-android");
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            if ("true".equals(properties.getProperty("mobile.android.enabled"))) {
+                manager.loadTargets("nbres:/com/jme3/gde/android/mobile-targets.xml");
+                manager.checkExtension(project);
+                manager.addRunConfiguration(project, "run-android", "Android Emulator", "run-android");
+                AndroidSdkTool.checkProject(project,
+                        properties.getProperty("mobile.android.target"),
+                        properties.getProperty("application.title"),
+                        "MainActivity",
+                        properties.getProperty("mobile.android.package"),
+                        properties.getProperty("main.class"));
+            } else {
+                manager.removeExtension(project);
+                try {
+                    FileObject folder = project.getProjectDirectory().getFileObject("mobile");
+                    if (folder != null) {
+                        folder.delete();
+                    }
+                    project.getProjectDirectory().refresh();
+                } catch (IOException ex) {
+                    Exceptions.printStackTrace(ex);
+                }
+            }
+            try {
+                properties.store();
+            } catch (IOException ioe) {
+                Exceptions.printStackTrace(ioe);
+            }
+        }
+
+        private void unZipFile(InputStream source, FileObject projectRoot) throws IOException {
+            try {
+                ZipInputStream str = new ZipInputStream(source);
+                ZipEntry entry;
+                while ((entry = str.getNextEntry()) != null) {
+                    if (entry.isDirectory()) {
+                        FileUtil.createFolder(projectRoot, entry.getName());
+                    } else {
+                        FileObject fo = FileUtil.createData(projectRoot, entry.getName());
+                        writeFile(str, fo);
+                    }
+                }
+            } finally {
+                source.close();
+            }
+        }
+
+        private void writeFile(ZipInputStream str, FileObject fo) throws IOException {
+            OutputStream out = fo.getOutputStream();
+            try {
+                FileUtil.copy(str, out);
+            } finally {
+                out.close();
+            }
+        }
+    }
+}

+ 149 - 0
jme3-android/src/com/jme3/gde/android/MobileCustomizerPanel.form

@@ -0,0 +1,149 @@
+<?xml version="1.1" encoding="UTF-8" ?>
+
+<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Component id="jCheckBox1" alignment="0" pref="394" max="32767" attributes="0"/>
+          <Component id="jLabel2" alignment="0" pref="394" max="32767" attributes="0"/>
+          <Group type="102" alignment="0" attributes="0">
+              <Component id="jLabel1" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jComboBox1" pref="278" max="32767" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+          <Group type="102" alignment="0" attributes="0">
+              <Component id="jLabel3" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jTextField1" pref="237" max="32767" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+          <Component id="jScrollPane1" alignment="0" pref="394" max="32767" attributes="0"/>
+          <Group type="102" alignment="0" attributes="0">
+              <Component id="jButton2" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <Component id="jLabel2" min="-2" max="-2" attributes="0"/>
+              <EmptySpace type="unrelated" max="-2" attributes="0"/>
+              <Component id="jCheckBox1" min="-2" max="-2" attributes="0"/>
+              <EmptySpace type="unrelated" max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jComboBox1" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace type="unrelated" max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="jLabel3" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jTextField1" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace pref="62" max="32767" attributes="0"/>
+              <Component id="jButton2" min="-2" max="-2" attributes="0"/>
+              <EmptySpace type="unrelated" max="-2" attributes="0"/>
+              <Component id="jScrollPane1" min="-2" max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Component class="javax.swing.JCheckBox" name="jCheckBox1">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="com/jme3/gde/android/Bundle.properties" key="MobileCustomizerPanel.jCheckBox1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel1">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="com/jme3/gde/android/Bundle.properties" key="MobileCustomizerPanel.jLabel1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel2">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="com/jme3/gde/android/Bundle.properties" key="MobileCustomizerPanel.jLabel2.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JComboBox" name="jComboBox1">
+      <Properties>
+        <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
+          <StringArray count="4">
+            <StringItem index="0" value="Item 1"/>
+            <StringItem index="1" value="Item 2"/>
+            <StringItem index="2" value="Item 3"/>
+            <StringItem index="3" value="Item 4"/>
+          </StringArray>
+        </Property>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel3">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="com/jme3/gde/android/Bundle.properties" key="MobileCustomizerPanel.jLabel3.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JTextField" name="jTextField1">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="com/jme3/gde/android/Bundle.properties" key="MobileCustomizerPanel.jTextField1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JButton" name="jButton2">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="com/jme3/gde/android/Bundle.properties" key="MobileCustomizerPanel.jButton2.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButton2ActionPerformed"/>
+      </Events>
+    </Component>
+    <Container class="javax.swing.JScrollPane" name="jScrollPane1">
+      <Properties>
+        <Property name="enabled" type="boolean" value="false"/>
+      </Properties>
+      <AuxValues>
+        <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+      </AuxValues>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+      <SubComponents>
+        <Component class="javax.swing.JTextArea" name="jTextArea1">
+          <Properties>
+            <Property name="columns" type="int" value="20"/>
+            <Property name="lineWrap" type="boolean" value="true"/>
+            <Property name="rows" type="int" value="5"/>
+            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+              <ResourceString bundle="com/jme3/gde/android/Bundle.properties" key="MobileCustomizerPanel.jTextArea1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+            </Property>
+            <Property name="wrapStyleWord" type="boolean" value="true"/>
+            <Property name="disabledTextColor" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
+              <Color blue="0" green="0" red="0" type="rgb"/>
+            </Property>
+          </Properties>
+        </Component>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>

+ 183 - 0
jme3-android/src/com/jme3/gde/android/MobileCustomizerPanel.java

@@ -0,0 +1,183 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+/*
+ * LwjglAppletCustomizerPanel.java
+ *
+ * Created on 11.11.2010, 16:56:53
+ */
+package com.jme3.gde.android;
+
+import com.jme3.gde.android.AndroidSdkTool.AndroidTarget;
+import com.jme3.gde.core.j2seproject.ProjectExtensionProperties;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ *
+ * @author normenhansen
+ */
+public class MobileCustomizerPanel extends javax.swing.JPanel implements ActionListener {
+
+    private ProjectExtensionProperties properties;
+
+    /** Creates new form LwjglAppletCustomizerPanel */
+    public MobileCustomizerPanel(ProjectExtensionProperties properties) {
+        this.properties = properties;
+        initComponents();
+        updateTargetList();
+        loadProperties();
+    }
+
+    private void updateTargetList() {
+        jComboBox1.removeAllItems();
+        List<AndroidTarget> targets = AndroidSdkTool.getTargetList();
+        for (Iterator<AndroidTarget> it = targets.iterator(); it.hasNext();) {
+            AndroidTarget androidTarget = it.next();
+            jComboBox1.addItem(androidTarget);
+        }
+    }
+
+    private void loadProperties() {
+        String str = properties.getProperty("mobile.android.enabled");
+        if ("true".equals(str)) {
+            jCheckBox1.setSelected(true);
+        } else {
+            jCheckBox1.setSelected(false);
+        }
+        if (properties.getProperty("mobile.android.target") != null) {
+            jComboBox1.setSelectedItem(properties.getProperty("mobile.android.target"));
+        }
+        if (properties.getProperty("mobile.android.package") != null) {
+            jTextField1.setText(properties.getProperty("mobile.android.package"));
+        }else{
+            jTextField1.setText("com.mycompany.mygame");
+        }
+    }
+
+    private void saveProperties() {
+        if (jCheckBox1.isSelected()) {
+            properties.setProperty("mobile.android.enabled", "true");
+        } else {
+            properties.setProperty("mobile.android.enabled", "");
+        }
+        //TODO: check properties
+        properties.setProperty("mobile.android.target", ((AndroidTarget) jComboBox1.getSelectedItem()).getName());
+        properties.setProperty("mobile.android.package", jTextField1.getText());
+    }
+
+    public void actionPerformed(ActionEvent e) {
+        saveProperties();
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jCheckBox1 = new javax.swing.JCheckBox();
+        jLabel1 = new javax.swing.JLabel();
+        jLabel2 = new javax.swing.JLabel();
+        jComboBox1 = new javax.swing.JComboBox();
+        jLabel3 = new javax.swing.JLabel();
+        jTextField1 = new javax.swing.JTextField();
+        jButton2 = new javax.swing.JButton();
+        jScrollPane1 = new javax.swing.JScrollPane();
+        jTextArea1 = new javax.swing.JTextArea();
+
+        jCheckBox1.setText(org.openide.util.NbBundle.getMessage(MobileCustomizerPanel.class, "MobileCustomizerPanel.jCheckBox1.text")); // NOI18N
+
+        jLabel1.setText(org.openide.util.NbBundle.getMessage(MobileCustomizerPanel.class, "MobileCustomizerPanel.jLabel1.text")); // NOI18N
+
+        jLabel2.setText(org.openide.util.NbBundle.getMessage(MobileCustomizerPanel.class, "MobileCustomizerPanel.jLabel2.text")); // NOI18N
+
+        jComboBox1.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
+
+        jLabel3.setText(org.openide.util.NbBundle.getMessage(MobileCustomizerPanel.class, "MobileCustomizerPanel.jLabel3.text")); // NOI18N
+
+        jTextField1.setText(org.openide.util.NbBundle.getMessage(MobileCustomizerPanel.class, "MobileCustomizerPanel.jTextField1.text")); // NOI18N
+
+        jButton2.setText(org.openide.util.NbBundle.getMessage(MobileCustomizerPanel.class, "MobileCustomizerPanel.jButton2.text")); // NOI18N
+        jButton2.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButton2ActionPerformed(evt);
+            }
+        });
+
+        jScrollPane1.setEnabled(false);
+
+        jTextArea1.setColumns(20);
+        jTextArea1.setLineWrap(true);
+        jTextArea1.setRows(5);
+        jTextArea1.setText(org.openide.util.NbBundle.getMessage(MobileCustomizerPanel.class, "MobileCustomizerPanel.jTextArea1.text")); // NOI18N
+        jTextArea1.setWrapStyleWord(true);
+        jTextArea1.setDisabledTextColor(new java.awt.Color(0, 0, 0));
+        jScrollPane1.setViewportView(jTextArea1);
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+        this.setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jCheckBox1, javax.swing.GroupLayout.DEFAULT_SIZE, 394, Short.MAX_VALUE)
+            .addComponent(jLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, 394, Short.MAX_VALUE)
+            .addGroup(layout.createSequentialGroup()
+                .addComponent(jLabel1)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jComboBox1, 0, 278, Short.MAX_VALUE)
+                .addContainerGap())
+            .addGroup(layout.createSequentialGroup()
+                .addComponent(jLabel3)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jTextField1, javax.swing.GroupLayout.DEFAULT_SIZE, 237, Short.MAX_VALUE)
+                .addContainerGap())
+            .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 394, Short.MAX_VALUE)
+            .addGroup(layout.createSequentialGroup()
+                .addComponent(jButton2)
+                .addContainerGap())
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addComponent(jLabel2)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                .addComponent(jCheckBox1)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(jLabel1)
+                    .addComponent(jComboBox1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(jLabel3)
+                    .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 62, Short.MAX_VALUE)
+                .addComponent(jButton2)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+        );
+    }// </editor-fold>//GEN-END:initComponents
+
+private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed
+    AndroidSdkTool.startAndroidTool(true);
+    updateTargetList();
+}//GEN-LAST:event_jButton2ActionPerformed
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton jButton2;
+    private javax.swing.JCheckBox jCheckBox1;
+    private javax.swing.JComboBox jComboBox1;
+    private javax.swing.JLabel jLabel1;
+    private javax.swing.JLabel jLabel2;
+    private javax.swing.JLabel jLabel3;
+    private javax.swing.JScrollPane jScrollPane1;
+    private javax.swing.JTextArea jTextArea1;
+    private javax.swing.JTextField jTextField1;
+    // End of variables declaration//GEN-END:variables
+}

+ 61 - 0
jme3-android/src/com/jme3/gde/android/OutputReader.java

@@ -0,0 +1,61 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.gde.android;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.netbeans.api.progress.ProgressHandle;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author normenhansen
+ */
+public class OutputReader implements Runnable {
+
+    private Thread thread;
+    private BufferedReader in;
+    private ProgressHandle progress;
+
+    public OutputReader(InputStream in) {
+        this.in = new BufferedReader(new InputStreamReader(in));
+    }
+
+    public OutputReader(BufferedReader in) {
+        this.in = in;
+    }
+
+    public void start() {
+        thread = new Thread(this);
+        thread.start();
+    }
+
+    public void run() {
+        try {
+            String line;
+            while ((line = in.readLine()) != null) {
+                if (line.trim().length() > 0) {
+                    if (progress != null) {
+                        progress.progress(line);
+                    } else {
+                        Logger.getLogger(this.getClass().getName()).log(Level.INFO, line);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            Exceptions.printStackTrace(e);
+        }
+    }
+
+    /**
+     * @param progress the progress to set
+     */
+    public void setProgress(ProgressHandle progress) {
+        this.progress = progress;
+    }
+}

+ 21 - 0
jme3-android/src/com/jme3/gde/android/jme3-android.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+To change this template, choose Tools | Templates
+and open the template in the editor.
+-->
+<!DOCTYPE library PUBLIC "-//NetBeans//DTD Library Declaration 1.0//EN" "http://www.netbeans.org/dtds/library-declaration-1_0.dtd">
+<library version="1.0">
+    <name>jme3-android</name>
+    <type>j2se</type>
+    <localizing-bundle>com.jme3.gde.android.Bundle</localizing-bundle>
+    <volume>
+        <type>classpath</type>
+        <resource>jar:nbinst://com.jme3.gde.android/libs/jMonkeyEngine3-android.jar!/</resource>
+    </volume>
+    <volume>
+        <type>src</type>
+    </volume>
+    <volume>
+        <type>javadoc</type>
+    </volume>
+</library>

+ 26 - 0
jme3-android/src/com/jme3/gde/android/layer.xml

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.2//EN" "http://www.netbeans.org/dtds/filesystem-1_2.dtd">
+<filesystem>
+    <!--folder name="Projects">
+
+        <folder name="org-netbeans-modules-java-j2seproject">
+
+            <folder name="Lookup">
+                <file name="com.jme3.gde.android.ImportantFilesNode$LookupProviderImpl.instance"/>
+            </folder>
+
+            <folder name="Nodes">
+                <file name="com.jme3.gde.android.ImportantFilesNode$ImportantFilesNodeFactoryImpl.instance">
+                    <attr name="position" intvalue="1210"/>
+                </file>
+            </folder>
+
+        </folder>
+
+    </folder-->
+    <folder name="org-netbeans-api-project-libraries">
+        <folder name="Libraries">
+            <file name="jme3-android.xml" url="jme3-android.xml"/>
+        </folder>
+    </folder>
+</filesystem>

+ 38 - 0
jme3-android/src/com/jme3/gde/android/mobile-targets.xml

@@ -0,0 +1,38 @@
+    <target name="run-android" depends="jar, -test-android-enabled, -copy-android-libs" if="is.android.enabled">
+        <ant dir="mobile" target="install"/>
+    </target>
+    
+    <target name="-clean-android">
+        <ant dir="mobile" target="clean"/>
+    </target>
+    
+    <target name="-mobile-deployment" depends="-test-android-enabled, -copy-android-libs" if="is.android.enabled">
+        <ant dir="mobile" target="release"/>
+        <copy todir="dist" verbose="false" flatten="true">
+            <!--exclude jme3 test data from core-->
+            <fileset dir="mobile/bin/">
+                <include name="**/*.apk"/>
+            </fileset>
+        </copy>
+    </target>
+    
+    <target name="-test-android-enabled">
+        <condition property="is.android.enabled">
+            <istrue value="${mobile.android.enabled}"/>
+        </condition>
+    </target>
+    
+    <target name="-copy-android-libs" if="is.android.enabled">
+        <property name="libs.jme3-android" location="${libs.jme3-android.classpath}"/>
+        <copy todir="mobile/libs" verbose="false" flatten="true">
+            <!--exclude jme3 test data from core-->
+            <fileset dir="dist/lib/">
+                <exclude name="jMonkeyEngine3.jar"/>
+                <exclude name="jME3-lwjgl-natives.jar"/>
+                <exclude name="lwjgl.jar"/>
+                <exclude name="jinput.jar"/>
+            </fileset>
+        </copy>
+        <copy file="${libs.jme3-android}" tofile="mobile/libs/jMonkeyEngine3.jar" verbose="false"/>
+        <copy file="${dist.jar}" todir="mobile/libs/" verbose="false"/>
+    </target>

+ 6 - 0
jme3-android/src/com/jme3/gde/android/properties/Bundle.properties

@@ -0,0 +1,6 @@
+OptionsCategory_Keywords_Mobile=Mobile
+OptionsCategory_Name_Mobile=Mobile
+MobilePanel.jLabel1.text=SDK Path:
+MobilePanel.jTextField1.text=jTextField1
+MobilePanel.jButton1.text=set..
+MobilePanel.jButton2.text=Run Android Target Configuration Utility

+ 76 - 0
jme3-android/src/com/jme3/gde/android/properties/MobileOptionsPanelController.java

@@ -0,0 +1,76 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.gde.android.properties;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import javax.swing.JComponent;
+import org.netbeans.spi.options.OptionsPanelController;
+import org.openide.util.HelpCtx;
+import org.openide.util.Lookup;
+
[email protected](categoryName = "#OptionsCategory_Name_Mobile",
+iconBase = "com/jme3/gde/android/properties/Phone_16.gif",
+keywords = "#OptionsCategory_Keywords_Mobile",
+keywordsCategory = "Mobile")
+public final class MobileOptionsPanelController extends OptionsPanelController {
+
+    private MobilePanel panel;
+    private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
+    private boolean changed;
+
+    public void update() {
+        getPanel().load();
+        changed = false;
+    }
+
+    public void applyChanges() {
+        getPanel().store();
+        changed = false;
+    }
+
+    public void cancel() {
+        // need not do anything special, if no changes have been persisted yet
+    }
+
+    public boolean isValid() {
+        return getPanel().valid();
+    }
+
+    public boolean isChanged() {
+        return changed;
+    }
+
+    public HelpCtx getHelpCtx() {
+        return null; // new HelpCtx("...ID") if you have a help set
+    }
+
+    public JComponent getComponent(Lookup masterLookup) {
+        return getPanel();
+    }
+
+    public void addPropertyChangeListener(PropertyChangeListener l) {
+        pcs.addPropertyChangeListener(l);
+    }
+
+    public void removePropertyChangeListener(PropertyChangeListener l) {
+        pcs.removePropertyChangeListener(l);
+    }
+
+    private MobilePanel getPanel() {
+        if (panel == null) {
+            panel = new MobilePanel(this);
+        }
+        return panel;
+    }
+
+    void changed() {
+        if (!changed) {
+            changed = true;
+            pcs.firePropertyChange(OptionsPanelController.PROP_CHANGED, false, true);
+        }
+        pcs.firePropertyChange(OptionsPanelController.PROP_VALID, null, null);
+    }
+}

+ 87 - 0
jme3-android/src/com/jme3/gde/android/properties/MobilePanel.form

@@ -0,0 +1,87 @@
+<?xml version="1.1" encoding="UTF-8" ?>
+
+<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" alignment="0" attributes="0">
+                      <Component id="jLabel1" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jTextField1" pref="318" max="32767" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jButton1" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <Component id="jButton2" alignment="0" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jTextField1" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jButton1" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace type="separate" max="-2" attributes="0"/>
+              <Component id="jButton2" min="-2" max="-2" attributes="0"/>
+              <EmptySpace pref="122" max="32767" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Component class="javax.swing.JLabel" name="jLabel1">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="com/jme3/gde/android/properties/Bundle.properties" key="MobilePanel.jLabel1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JTextField" name="jTextField1">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="com/jme3/gde/android/properties/Bundle.properties" key="MobilePanel.jTextField1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JButton" name="jButton1">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="com/jme3/gde/android/properties/Bundle.properties" key="MobilePanel.jButton1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButton1ActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JButton" name="jButton2">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="com/jme3/gde/android/properties/Bundle.properties" key="MobilePanel.jButton2.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButton2ActionPerformed"/>
+      </Events>
+    </Component>
+  </SubComponents>
+</Form>

+ 153 - 0
jme3-android/src/com/jme3/gde/android/properties/MobilePanel.java

@@ -0,0 +1,153 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.gde.android.properties;
+
+import com.jme3.gde.android.AndroidSdkTool;
+import java.io.File;
+import org.openide.DialogDisplayer;
+import org.openide.NotifyDescriptor;
+import org.openide.NotifyDescriptor.Message;
+import org.openide.filesystems.FileChooserBuilder;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.util.NbPreferences;
+
+final class MobilePanel extends javax.swing.JPanel {
+
+    private final MobileOptionsPanelController controller;
+
+    MobilePanel(MobileOptionsPanelController controller) {
+        this.controller = controller;
+        initComponents();
+        // TODO listen to changes in form fields and call controller.changed()
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jLabel1 = new javax.swing.JLabel();
+        jTextField1 = new javax.swing.JTextField();
+        jButton1 = new javax.swing.JButton();
+        jButton2 = new javax.swing.JButton();
+
+        org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(MobilePanel.class, "MobilePanel.jLabel1.text")); // NOI18N
+
+        jTextField1.setText(org.openide.util.NbBundle.getMessage(MobilePanel.class, "MobilePanel.jTextField1.text")); // NOI18N
+
+        org.openide.awt.Mnemonics.setLocalizedText(jButton1, org.openide.util.NbBundle.getMessage(MobilePanel.class, "MobilePanel.jButton1.text")); // NOI18N
+        jButton1.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButton1ActionPerformed(evt);
+            }
+        });
+
+        org.openide.awt.Mnemonics.setLocalizedText(jButton2, org.openide.util.NbBundle.getMessage(MobilePanel.class, "MobilePanel.jButton2.text")); // NOI18N
+        jButton2.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButton2ActionPerformed(evt);
+            }
+        });
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+        this.setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(layout.createSequentialGroup()
+                        .addComponent(jLabel1)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(jTextField1, javax.swing.GroupLayout.DEFAULT_SIZE, 318, Short.MAX_VALUE)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(jButton1))
+                    .addComponent(jButton2))
+                .addContainerGap())
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(jLabel1)
+                    .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(jButton1))
+                .addGap(18, 18, 18)
+                .addComponent(jButton2)
+                .addContainerGap(122, Short.MAX_VALUE))
+        );
+    }// </editor-fold>//GEN-END:initComponents
+
+private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
+    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();
+            jTextField1.setText(name);
+        }
+    }
+}//GEN-LAST:event_jButton1ActionPerformed
+
+private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed
+    AndroidSdkTool.startAndroidTool();
+}//GEN-LAST:event_jButton2ActionPerformed
+
+    void load() {
+//         jTextField2.setText(NbPreferences.forModule(AndroidSdkTool.class).get("assetpack_path", null));
+        jTextField1.setText(NbPreferences.forModule(AndroidSdkTool.class).get("sdk_path", null));
+//         jPasswordField1.setText(NbPreferences.forModule(AndroidSdkTool.class).get("assetpack_pass", null));
+    }
+
+    void store() {
+//        NbPreferences.forModule(AndroidSdkTool.class).put("assetpack_path", jTextField2.getText());
+        NbPreferences.forModule(AndroidSdkTool.class).put("sdk_path", jTextField1.getText());
+//        NbPreferences.forModule(AndroidSdkTool.class).put("assetpack_pass", new String(jPasswordField1.getPassword()));
+    }
+//    void load() {
+//        // TODO read settings and initialize GUI
+//        // Example:        
+//        // someCheckBox.setSelected(Preferences.userNodeForPackage(MobilePanel.class).getBoolean("someFlag", false));
+//        // or for org.openide.util with API spec. version >= 7.4:
+//        // someCheckBox.setSelected(NbPreferences.forModule(MobilePanel.class).getBoolean("someFlag", false));
+//        // or:
+//        // someTextField.setText(SomeSystemOption.getDefault().getSomeStringProperty());
+//    }
+//
+//    void store() {
+//        // TODO store modified settings
+//        // Example:
+//        // Preferences.userNodeForPackage(MobilePanel.class).putBoolean("someFlag", someCheckBox.isSelected());
+//        // or for org.openide.util with API spec. version >= 7.4:
+//        // NbPreferences.forModule(MobilePanel.class).putBoolean("someFlag", someCheckBox.isSelected());
+//        // or:
+//        // SomeSystemOption.getDefault().setSomeStringProperty(someTextField.getText());
+//    }
+
+    boolean valid() {
+        // TODO check whether form is consistent and complete
+        return true;
+    }
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton jButton1;
+    private javax.swing.JButton jButton2;
+    private javax.swing.JLabel jLabel1;
+    private javax.swing.JTextField jTextField1;
+    // End of variables declaration//GEN-END:variables
+}

BIN
jme3-android/src/com/jme3/gde/android/properties/Phone_16.gif


+ 2 - 1
nbproject/project.properties

@@ -43,7 +43,8 @@ modules=\
     ${project.com.jme3.gde.codecheck}:\
     ${project.com.jme3.gde.obfuscate}:\
     ${project.com.jme3.gde.blender}:\
-    ${project.com.jme3.gde.angelfont}
+    ${project.com.jme3.gde.angelfont}:\
+    ${project.com.jme3.gde.android}
 project.com.jme3.gde.android=jme3-android
 project.com.jme3.gde.angelfont=jme3-angelfont
 project.com.jme3.gde.blender=jme3-blender