summaryrefslogtreecommitdiff
path: root/platform/android
diff options
context:
space:
mode:
authorJuan Linietsky <reduzio@gmail.com>2014-02-09 22:10:30 -0300
committerJuan Linietsky <reduzio@gmail.com>2014-02-09 22:10:30 -0300
commit0b806ee0fc9097fa7bda7ac0109191c9c5e0a1ac (patch)
tree276c4d099e178eb67fbd14f61d77b05e3808e9e3 /platform/android
parent0e49da1687bc8192ed210947da52c9e5c5f301bb (diff)
GODOT IS OPEN SOURCE
Diffstat (limited to 'platform/android')
-rw-r--r--platform/android/.old/SCsub22
-rw-r--r--platform/android/.old/audio_driver_android.cpp104
-rw-r--r--platform/android/.old/audio_driver_android.h29
-rw-r--r--platform/android/.old/context_gl_android.cpp38
-rw-r--r--platform/android/.old/context_gl_android.h24
-rw-r--r--platform/android/.old/detect.py107
-rw-r--r--platform/android/.old/dir_access_jandroid.cpp217
-rw-r--r--platform/android/.old/dir_access_jandroid.h63
-rw-r--r--platform/android/.old/file_access_jandroid.cpp204
-rw-r--r--platform/android/.old/file_access_jandroid.h56
-rw-r--r--platform/android/.old/gdb.setup.base3
-rw-r--r--platform/android/.old/java/AndroidManifest.xml22
-rw-r--r--platform/android/.old/java/build.properties17
-rw-r--r--platform/android/.old/java/build.xml79
-rw-r--r--platform/android/.old/java/default.properties11
-rwxr-xr-xplatform/android/.old/java/libs/armeabi/gdbserverbin0 -> 125208 bytes
-rw-r--r--platform/android/.old/java/local.properties10
-rw-r--r--platform/android/.old/java/proguard.cfg36
-rw-r--r--platform/android/.old/java/res/drawable-hdpi/icon.pngbin0 -> 4147 bytes
-rw-r--r--platform/android/.old/java/res/drawable-ldpi/icon.pngbin0 -> 1723 bytes
-rw-r--r--platform/android/.old/java/res/drawable-mdpi/icon.pngbin0 -> 2574 bytes
-rw-r--r--platform/android/.old/java/res/values/strings.xml4
-rw-r--r--platform/android/.old/java/src/com/android/godot/Godot.java85
-rw-r--r--platform/android/.old/java/src/com/android/godot/GodotIO.java277
-rw-r--r--platform/android/.old/java/src/com/android/godot/GodotLib.java22
-rw-r--r--platform/android/.old/java/src/com/android/godot/GodotView.java319
-rw-r--r--platform/android/.old/java_glue.cpp181
-rw-r--r--platform/android/.old/java_glue.h16
-rw-r--r--platform/android/.old/os_android.cpp426
-rw-r--r--platform/android/.old/os_android.h108
-rw-r--r--platform/android/.old/platform_config.h1
-rwxr-xr-xplatform/android/.old/run_debug.sh40
-rw-r--r--platform/android/AndroidManifest.xml.template40
-rw-r--r--platform/android/SCsub66
-rw-r--r--platform/android/android_native_app_glue.c437
-rw-r--r--platform/android/android_native_app_glue.h378
-rw-r--r--platform/android/audio_driver_android.cpp393
-rw-r--r--platform/android/audio_driver_android.h105
-rw-r--r--platform/android/audio_driver_jandroid.cpp248
-rw-r--r--platform/android/audio_driver_jandroid.h82
-rw-r--r--platform/android/detect.py175
-rw-r--r--platform/android/dir_access_android.cpp189
-rw-r--r--platform/android/dir_access_android.h82
-rw-r--r--platform/android/dir_access_jandroid.cpp241
-rw-r--r--platform/android/dir_access_jandroid.h90
-rw-r--r--platform/android/export/export.cpp1229
-rw-r--r--platform/android/export/export.h3
-rw-r--r--platform/android/file_access_android.cpp187
-rw-r--r--platform/android/file_access_android.h82
-rw-r--r--platform/android/file_access_jandroid.cpp253
-rw-r--r--platform/android/file_access_jandroid.h87
-rw-r--r--platform/android/globals/global_defaults.cpp13
-rw-r--r--platform/android/globals/global_defaults.h3
-rw-r--r--platform/android/godot_android.cpp993
-rw-r--r--platform/android/java/ant.properties22
-rw-r--r--platform/android/java/build.properties17
-rw-r--r--platform/android/java/build.xml92
-rw-r--r--platform/android/java/default.properties11
-rw-r--r--platform/android/java/my-release-key.keystorebin0 -> 2218 bytes
-rw-r--r--platform/android/java/proguard-project.txt20
-rw-r--r--platform/android/java/proguard.cfg36
-rw-r--r--platform/android/java/res/drawable/icon.pngbin0 -> 91728 bytes
-rw-r--r--platform/android/java/res/values-ar/strings.xml4
-rw-r--r--platform/android/java/res/values-bg/strings.xml4
-rw-r--r--platform/android/java/res/values-ca/strings.xml4
-rw-r--r--platform/android/java/res/values-cs/strings.xml4
-rw-r--r--platform/android/java/res/values-da/strings.xml4
-rw-r--r--platform/android/java/res/values-de/strings.xml4
-rw-r--r--platform/android/java/res/values-el/strings.xml4
-rw-r--r--platform/android/java/res/values-en/strings.xml4
-rw-r--r--platform/android/java/res/values-es-rES/strings.xml4
-rw-r--r--platform/android/java/res/values-es/strings.xml4
-rw-r--r--platform/android/java/res/values-fi/strings.xml4
-rw-r--r--platform/android/java/res/values-fr/strings.xml4
-rw-r--r--platform/android/java/res/values-he/strings.xml4
-rw-r--r--platform/android/java/res/values-hi/strings.xml4
-rw-r--r--platform/android/java/res/values-hr/strings.xml4
-rw-r--r--platform/android/java/res/values-hu/strings.xml4
-rw-r--r--platform/android/java/res/values-id/strings.xml4
-rw-r--r--platform/android/java/res/values-it/strings.xml4
-rw-r--r--platform/android/java/res/values-ja/strings.xml4
-rw-r--r--platform/android/java/res/values-ko/strings.xml4
-rw-r--r--platform/android/java/res/values-lt/strings.xml4
-rw-r--r--platform/android/java/res/values-lv/strings.xml4
-rw-r--r--platform/android/java/res/values-nb/strings.xml4
-rw-r--r--platform/android/java/res/values-nl/strings.xml4
-rw-r--r--platform/android/java/res/values-pl/strings.xml4
-rw-r--r--platform/android/java/res/values-pt/strings.xml4
-rw-r--r--platform/android/java/res/values-ro/strings.xml4
-rw-r--r--platform/android/java/res/values-ru/strings.xml4
-rw-r--r--platform/android/java/res/values-sk/strings.xml4
-rw-r--r--platform/android/java/res/values-sl/strings.xml4
-rw-r--r--platform/android/java/res/values-sr/strings.xml4
-rw-r--r--platform/android/java/res/values-sv/strings.xml4
-rw-r--r--platform/android/java/res/values-th/strings.xml4
-rw-r--r--platform/android/java/res/values-tl/strings.xml4
-rw-r--r--platform/android/java/res/values-tr/strings.xml4
-rw-r--r--platform/android/java/res/values-uk/strings.xml4
-rw-r--r--platform/android/java/res/values-vi/strings.xml4
-rw-r--r--platform/android/java/res/values-zh/strings.xml4
-rw-r--r--platform/android/java/res/values/strings.xml7
-rw-r--r--platform/android/java/src/com/android/godot/Dictionary.java80
-rw-r--r--platform/android/java/src/com/android/godot/Godot.java300
-rw-r--r--platform/android/java/src/com/android/godot/GodotIO.java514
-rw-r--r--platform/android/java/src/com/android/godot/GodotLib.java63
-rw-r--r--platform/android/java/src/com/android/godot/GodotView.java378
-rw-r--r--platform/android/java_glue.cpp1153
-rw-r--r--platform/android/java_glue.h58
-rw-r--r--platform/android/logo.pngbin0 -> 1474 bytes
-rw-r--r--platform/android/os_android.cpp709
-rw-r--r--platform/android/os_android.h197
-rw-r--r--platform/android/platform_config.h29
-rw-r--r--platform/android/project.properties.template15
-rwxr-xr-xplatform/android/sign.sh9
-rw-r--r--platform/android/thread_jandroid.cpp135
-rw-r--r--platform/android/thread_jandroid.h82
116 files changed, 11976 insertions, 0 deletions
diff --git a/platform/android/.old/SCsub b/platform/android/.old/SCsub
new file mode 100644
index 0000000000..59e6d10b85
--- /dev/null
+++ b/platform/android/.old/SCsub
@@ -0,0 +1,22 @@
+Import('env')
+
+android_files = [
+
+ 'audio_driver_android.cpp',
+ 'file_access_jandroid.cpp',
+ 'dir_access_jandroid.cpp',
+ 'os_android.cpp',
+ 'java_glue.cpp'
+]
+
+#env.Depends('#core/math/vector3.h', 'vector3_psp.h')
+
+#obj = env.SharedObject('godot_android.cpp')
+
+android_objects=[]
+for x in android_files:
+ android_objects.append( env.SharedObject( x ) )
+
+prog = None
+
+env.SharedLibrary("#platform/jandroid/libgodot_android.so",[android_objects])
diff --git a/platform/android/.old/audio_driver_android.cpp b/platform/android/.old/audio_driver_android.cpp
new file mode 100644
index 0000000000..7e2d065d65
--- /dev/null
+++ b/platform/android/.old/audio_driver_android.cpp
@@ -0,0 +1,104 @@
+#include "audio_driver_android.h"
+
+AudioDriverAndroid* AudioDriverAndroid::s_ad=NULL;
+
+const char* AudioDriverAndroid::get_name() const {
+
+ return "Android";
+}
+
+#if 0
+int AudioDriverAndroid::thread_func(SceSize args, void *argp) {
+
+ AudioDriverAndroid* ad = s_ad;
+ sceAudioOutput2Reserve(AUDIO_OUTPUT_SAMPLE);
+
+ int half=0;
+ while(!ad->exit_thread) {
+
+ int16_t *ptr = &ad->outbuff[AUDIO_OUTPUT_SAMPLE*2*half];
+
+
+
+ if (!ad->active) {
+
+ for(int i=0;i<AUDIO_OUTPUT_SAMPLE*2;i++) {
+ ptr[i]=0;
+ }
+
+ } else {
+
+ //printf("samples: %i\n",AUDIO_OUTPUT_SAMPLE);
+ ad->lock();
+
+ ad->audio_server_process(AUDIO_OUTPUT_SAMPLE,ad->outbuff_32);
+
+ ad->unlock();
+
+ const int32_t* src_buff=ad->outbuff_32;
+
+ for(int i=0;i<AUDIO_OUTPUT_SAMPLE*2;i++) {
+
+ ptr[i]=src_buff[i]>>16;
+ }
+ }
+
+
+ /* Output 16-bit PCM STEREO data that is in pcmBuf without changing the volume */
+ sceAudioOutput2OutputBlocking(
+ SCE_AUDIO_VOLUME_0dB*3, //0db at 0x8000, that's obvious
+ ptr
+ );
+
+ if (half)
+ half=0;
+ else
+ half=1;
+
+ }
+
+ sceAudioOutput2Release();
+
+ sceKernelExitThread(SCE_KERNEL_EXIT_SUCCESS);
+ ad->thread_exited=true;
+ return SCE_KERNEL_EXIT_SUCCESS;
+
+}
+
+#endif
+Error AudioDriverAndroid::init(){
+
+ return OK;
+
+
+}
+void AudioDriverAndroid::start(){
+
+
+}
+int AudioDriverAndroid::get_mix_rate() const {
+
+ return 44100;
+}
+AudioDriverSW::OutputFormat AudioDriverAndroid::get_output_format() const{
+
+ return OUTPUT_STEREO;
+}
+void AudioDriverAndroid::lock(){
+
+
+}
+void AudioDriverAndroid::unlock() {
+
+
+}
+void AudioDriverAndroid::finish(){
+
+ }
+
+
+AudioDriverAndroid::AudioDriverAndroid()
+{
+ s_ad=this;
+}
+
diff --git a/platform/android/.old/audio_driver_android.h b/platform/android/.old/audio_driver_android.h
new file mode 100644
index 0000000000..08fbaa927e
--- /dev/null
+++ b/platform/android/.old/audio_driver_android.h
@@ -0,0 +1,29 @@
+#ifndef AUDIO_DRIVER_ANDROID_H
+#define AUDIO_DRIVER_ANDROID_H
+
+#include "servers/audio/audio_server_sw.h"
+
+class AudioDriverAndroid : public AudioDriverSW {
+
+
+ static AudioDriverAndroid* s_ad;
+
+public:
+
+ void set_singleton();
+
+ virtual const char* get_name() const;
+
+ virtual Error init();
+ virtual void start();
+ virtual int get_mix_rate() const ;
+ virtual OutputFormat get_output_format() const;
+ virtual void lock();
+ virtual void unlock();
+ virtual void finish();
+
+
+ AudioDriverAndroid();
+};
+
+#endif // AUDIO_DRIVER_ANDROID_H
diff --git a/platform/android/.old/context_gl_android.cpp b/platform/android/.old/context_gl_android.cpp
new file mode 100644
index 0000000000..e48ed2e7f9
--- /dev/null
+++ b/platform/android/.old/context_gl_android.cpp
@@ -0,0 +1,38 @@
+#include "context_gl_android.h"
+
+#include <GLES2/gl2.h>
+#include "os/os.h"
+void ContextGLAndroid::make_current() {
+
+};
+
+int ContextGLAndroid::get_window_width() {
+
+ return OS::get_singleton()->get_default_video_mode().width;
+};
+
+int ContextGLAndroid::get_window_height() {
+
+ return OS::get_singleton()->get_default_video_mode().height;
+
+};
+
+void ContextGLAndroid::swap_buffers() {
+
+};
+
+Error ContextGLAndroid::initialize() {
+
+ return OK;
+};
+
+
+ContextGLAndroid::ContextGLAndroid() {
+
+
+};
+
+ContextGLAndroid::~ContextGLAndroid() {
+
+};
+
diff --git a/platform/android/.old/context_gl_android.h b/platform/android/.old/context_gl_android.h
new file mode 100644
index 0000000000..bf09d08ad2
--- /dev/null
+++ b/platform/android/.old/context_gl_android.h
@@ -0,0 +1,24 @@
+#ifndef CONTEXT_GL_ANDROID_H
+#define CONTEXT_GL_ANDROID_H
+
+class ContextGLAndroid : public ContextGL {
+
+ enum {
+ COMMAND_BUFFER_SIZE = 1024 * 1024,
+ };
+
+public:
+
+ virtual void make_current();
+
+ virtual int get_window_width();
+ virtual int get_window_height();
+ virtual void swap_buffers();
+
+ virtual Error initialize();
+
+ ContextGLAndroid();
+ ~ContextGLAndroid();
+};
+
+#endif // CONTEXT_GL_ANDROID_H
diff --git a/platform/android/.old/detect.py b/platform/android/.old/detect.py
new file mode 100644
index 0000000000..c29b56aed4
--- /dev/null
+++ b/platform/android/.old/detect.py
@@ -0,0 +1,107 @@
+import os
+import sys
+import string
+
+def can_build():
+
+ import os
+ if (not os.environ.has_key("ANDROID_NDK_ROOT")):
+ print("ANDROID_NDK_ROOT not present, Android disabled.")
+ return False
+ return True
+
+def get_opts():
+
+ return [
+ ('ANDROID_NDK_ROOT', 'the path to Android NDK', os.environ.get("ANDROID_NDK_ROOT", 0)),
+ ('NDK_TOOLCHAIN', 'toolchain to use for the NDK',"arm-eabi-4.4.0"),
+ #android 2.2
+# ('NDK_PLATFORM', 'platform to use for the NDK',"android-8"),
+# ('NDK_TARGET', 'toolchain to use for the NDK',"arm-linux-androideabi-4.4.3"),
+ ]
+
+def get_flags():
+
+ return [
+ ('lua', 'no'),
+ ('tools', 'no'),
+ ('nedmalloc', 'no'),
+ ]
+
+
+
+def configure(env):
+
+
+ print("Godot Android!!!!!")
+
+ env.Append(CPPPATH=['#platform/android'])
+
+ env['OBJSUFFIX'] = ".jandroid.o"
+ env['LIBSUFFIX'] = ".jandroid.a"
+ env['PROGSUFFIX'] = ".jandroid"
+
+ gcc_path=env["ANDROID_NDK_ROOT"]+"/toolchains/"+env["NDK_TARGET"]+"/prebuilt/";
+
+ if (sys.platform.find("linux")==0):
+ gcc_path=gcc_path+"/linux-x86/bin"
+ elif (sys.platform=="darwin"):
+ gcc_path=gcc_path+"/darwin-x86/bin" #this may be wrong
+ elif (os.name=="nt"):
+ gcc_path=gcc_path+"/windows-x86/bin" #this may be wrong
+
+
+
+ env['ENV']['PATH'] = gcc_path+":"+env['ENV']['PATH']
+
+ env['CC'] = gcc_path+'/arm-linux-androideabi-gcc'
+ env['CXX'] = gcc_path+'/arm-linux-androideabi-g++'
+ env['AR'] = gcc_path+"/arm-linux-androideabi-ar"
+
+ import string
+ #include path
+ gcc_include=env["ANDROID_NDK_ROOT"]+"/platforms/"+env["NDK_PLATFORM"]+"/arch-arm/usr/include"
+ ld_sysroot=env["ANDROID_NDK_ROOT"]+"/platforms/"+env["NDK_PLATFORM"]+"/arch-arm"
+ ld_path=env["ANDROID_NDK_ROOT"]+"/platforms/"+env["NDK_PLATFORM"]+"/arch-arm/usr/lib"
+ #cxx_include=env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/system/include"
+ #env.Append(CPPPATH=[gcc_include,cxx_include])
+ env['CCFLAGS'] = string.split('-DNO_THREADS -DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -fno-exceptions -mthumb -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED ')
+
+ env.Append(LDPATH=[ld_path])
+ env.Append(LIBS=['c','m','stdc++','log','GLESv2'])
+
+ env["LINKFLAGS"]= string.split(" -g --sysroot="+ld_sysroot+" -Wl,--no-undefined -Wl,-z,noexecstack")
+ env.Append(LINKFLAGS=["-Wl,-soname,libgodot_android.so"])
+
+ if (env["target"]=="release"):
+
+ env.Append(CCFLAGS=['-O2', '-ffast-math','-fomit-frame-pointer'])
+ env['OBJSUFFIX'] = "_opt"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = "_opt"+env['LIBSUFFIX']
+
+ elif (env["target"]=="debug"):
+
+ env.Append(CCFLAGS=['-D_DEBUG', '-g', '-Wall', '-O0', '-DDEBUG_ENABLED'])
+ env.Append(CPPFLAGS=['-DDEBUG_MEMORY_ALLOC'])
+
+ env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED','-DNO_FCNTL'])
+
+ env['neon_enabled']=True
+ env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED', '-DNO_FCNTL','-DMPC_FIXED_POINT'])
+# env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED','-DMPC_FIXED_POINT'])
+ if (env['android_stl']=='yes'):
+ #env.Append(CCFLAGS=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/system/include"])
+ env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.4.3/include"])
+ env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.4.3/libs/armeabi/include"])
+ env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.4.3/libs/armeabi"])
+ env.Append(LIBS=["gnustl_static","supc++"])
+ #env.Append(CCFLAGS=["-I"+env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/stlport/stlport"])
+ #env.Append(CCFLAGS=["-I"+env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/libs/armeabi/include"])
+ #env.Append(LINKFLAGS=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/libs/armeabi/libstdc++.a"])
+ else:
+
+ env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gabi++/include"])
+ env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cpufeatures"])
+ env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gabi++/libs/armeabi"])
+ env.Append(LIBS=['gabi++_static'])
+ env.Append(CCFLAGS=["-fno-exceptions",'-DNO_SAFE_CAST'])
diff --git a/platform/android/.old/dir_access_jandroid.cpp b/platform/android/.old/dir_access_jandroid.cpp
new file mode 100644
index 0000000000..649a25a902
--- /dev/null
+++ b/platform/android/.old/dir_access_jandroid.cpp
@@ -0,0 +1,217 @@
+#include "dir_access_jandroid.h"
+#include "file_access_jandroid.h"
+
+jobject DirAccessJAndroid::io=NULL;
+jclass DirAccessJAndroid::cls=NULL;
+JNIEnv * DirAccessJAndroid::env=NULL;
+jmethodID DirAccessJAndroid::_dir_open=NULL;
+jmethodID DirAccessJAndroid::_dir_next=NULL;
+jmethodID DirAccessJAndroid::_dir_close=NULL;
+
+
+DirAccess *DirAccessJAndroid::create_fs() {
+
+ return memnew(DirAccessJAndroid);
+}
+
+bool DirAccessJAndroid::list_dir_begin() {
+
+ list_dir_end();
+
+ jstring js = env->NewStringUTF(current_dir.utf8().get_data());
+ int res = env->CallIntMethod(io,_dir_open,js);
+ if (res<=0)
+ return true;
+
+ id=res;
+
+ return false;
+}
+
+String DirAccessJAndroid::get_next(){
+
+ ERR_FAIL_COND_V(id==0,"");
+
+ jstring str= (jstring)env->CallObjectMethod(io,_dir_next,id);
+ if (!str)
+ return "";
+
+ int sl = env->GetStringLength(str);
+ if (sl==0) {
+ env->DeleteLocalRef((jobject)str);
+ return "";
+ }
+
+ CharString cs;
+ cs.resize(sl+1);
+ env->GetStringRegion(str,0,sl,(jchar*)&cs[0]);
+ cs[sl]=0;
+
+ String ret;
+ ret.parse_utf8(&cs[0]);
+ env->DeleteLocalRef((jobject)str);
+
+ return ret;
+
+}
+bool DirAccessJAndroid::current_is_dir() const{
+
+ String sd;
+ if (current_dir=="")
+ sd=current;
+ else
+ sd=current_dir+"/"+current;
+
+ jstring js = env->NewStringUTF(sd.utf8().get_data());
+
+ int res = env->CallIntMethod(io,_dir_open,js);
+ if (res<=0)
+ return false;
+
+ env->CallObjectMethod(io,_dir_close,res);
+
+
+ return true;
+}
+void DirAccessJAndroid::list_dir_end(){
+
+ if (id==0)
+ return;
+
+ env->CallObjectMethod(io,_dir_close,id);
+ id=0;
+
+
+}
+
+int DirAccessJAndroid::get_drive_count(){
+
+ return 0;
+}
+String DirAccessJAndroid::get_drive(int p_drive){
+
+ return "";
+}
+
+Error DirAccessJAndroid::change_dir(String p_dir){
+
+ p_dir=p_dir.simplify_path();
+
+ if (p_dir=="" || p_dir=="." || (p_dir==".." && current_dir==""))
+ return OK;
+
+ String new_dir;
+
+ if (p_dir.begins_with("/"))
+ new_dir=p_dir.substr(1,p_dir.length());
+ else if (p_dir.begins_with("res://"))
+ new_dir=p_dir.substr(6,p_dir.length());
+ else //relative
+ new_dir=new_dir+"/"+p_dir;
+
+//test if newdir exists
+ new_dir=new_dir.simplify_path();
+
+ jstring js = env->NewStringUTF(new_dir.utf8().get_data());
+ int res = env->CallIntMethod(io,_dir_open,js);
+ if (res<=0)
+ return ERR_INVALID_PARAMETER;
+
+ env->CallObjectMethod(io,_dir_close,res);
+
+
+
+ return OK;
+}
+
+String DirAccessJAndroid::get_current_dir(){
+
+ return "/"+current_dir;
+}
+String DirAccessJAndroid::get_dir_separator() const{
+
+ return "/";
+}
+
+bool DirAccessJAndroid::file_exists(String p_file){
+
+ String sd;
+ if (current_dir=="")
+ sd=p_file;
+ else
+ sd=current_dir+"/"+p_file;
+
+ FileAccessJAndroid *f = memnew(FileAccessJAndroid);
+ bool exists = f->file_exists(sd);
+ memdelete(f);
+
+ return exists;
+}
+
+uint64_t DirAccessJAndroid::get_modified_time(String p_file){
+
+ return 0;
+}
+
+Error DirAccessJAndroid::make_dir(String p_dir){
+
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+}
+
+Error DirAccessJAndroid::rename(String p_from, String p_to){
+
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+}
+Error DirAccessJAndroid::remove(String p_name){
+
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+}
+
+//FileType get_file_type() const;
+size_t DirAccessJAndroid::get_space_left() {
+
+ return 0;
+}
+
+void DirAccessJAndroid::make_default() {
+
+ instance_func=create_fs;
+}
+
+void DirAccessJAndroid::setup( JNIEnv *p_env, jobject p_io) {
+
+
+ env=p_env;
+ io=p_io;
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP7");
+
+ jclass c = env->GetObjectClass(io);
+ cls = (jclass)env->NewGlobalRef(c);
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP8");
+
+ _dir_open = env->GetMethodID(cls, "dir_open", "(Ljava/lang/String;)I");
+ if(_dir_open != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _dir_open ok!!");
+ }
+ _dir_next = env->GetMethodID(cls, "dir_next", "(I)Ljava/lang/String;");
+ if(_dir_next != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _dir_next ok!!");
+ }
+ _dir_close = env->GetMethodID(cls, "dir_close", "(I)V");
+ if(_dir_close != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _dir_close ok!!");
+ }
+
+// (*env)->CallVoidMethod(env,obj,aMethodID, myvar);
+}
+
+
+DirAccessJAndroid::DirAccessJAndroid() {
+
+ id=0;
+}
+
+DirAccessJAndroid::~DirAccessJAndroid() {
+
+ list_dir_end();;
+}
diff --git a/platform/android/.old/dir_access_jandroid.h b/platform/android/.old/dir_access_jandroid.h
new file mode 100644
index 0000000000..80973004aa
--- /dev/null
+++ b/platform/android/.old/dir_access_jandroid.h
@@ -0,0 +1,63 @@
+#ifndef DIR_ACCESS_JANDROID_H
+#define DIR_ACCESS_JANDROID_H
+
+#include "java_glue.h"
+#include "os/dir_access.h"
+#include <stdio.h>
+
+
+class DirAccessJAndroid : public DirAccess {
+
+ //AAssetDir* aad;
+
+ static jobject io;
+ static jclass cls;
+
+ static jmethodID _dir_open;
+ static jmethodID _dir_next;
+ static jmethodID _dir_close;
+
+ static JNIEnv * env;
+
+ int id;
+
+ String current_dir;
+ String current;
+
+ static DirAccess *create_fs();
+
+public:
+
+ virtual bool list_dir_begin(); ///< This starts dir listing
+ virtual String get_next();
+ virtual bool current_is_dir() const;
+ virtual void list_dir_end(); ///<
+
+ virtual int get_drive_count();
+ virtual String get_drive(int p_drive);
+
+ virtual Error change_dir(String p_dir); ///< can be relative or absolute, return false on success
+ virtual String get_current_dir(); ///< return current dir location
+ virtual String get_dir_separator() const ;
+
+ virtual bool file_exists(String p_file);
+ virtual uint64_t get_modified_time(String p_file);
+
+ virtual Error make_dir(String p_dir);
+
+ virtual Error rename(String p_from, String p_to);
+ virtual Error remove(String p_name);
+
+ //virtual FileType get_file_type() const;
+ size_t get_space_left();
+
+ static void make_default();
+
+ static void setup( JNIEnv *env, jobject io);
+ static void update_env( JNIEnv *p_env) { env=p_env; }
+
+ DirAccessJAndroid();
+ ~DirAccessJAndroid();
+};
+
+#endif // DIR_ACCESS_JANDROID_H
diff --git a/platform/android/.old/file_access_jandroid.cpp b/platform/android/.old/file_access_jandroid.cpp
new file mode 100644
index 0000000000..96c064f9f5
--- /dev/null
+++ b/platform/android/.old/file_access_jandroid.cpp
@@ -0,0 +1,204 @@
+#include "file_access_jandroid.h"
+#include "os/os.h"
+#include <unistd.h>
+
+jobject FileAccessJAndroid::io=NULL;
+jclass FileAccessJAndroid::cls;
+jmethodID FileAccessJAndroid::_file_open=0;
+jmethodID FileAccessJAndroid::_file_get_size=0;
+jmethodID FileAccessJAndroid::_file_seek=0;
+jmethodID FileAccessJAndroid::_file_read=0;
+jmethodID FileAccessJAndroid::_file_tell=0;
+jmethodID FileAccessJAndroid::_file_eof=0;
+jmethodID FileAccessJAndroid::_file_close=0;
+
+
+JNIEnv * FileAccessJAndroid::env=NULL;
+
+void FileAccessJAndroid::make_default() {
+
+ create_func=create_jandroid;
+}
+
+FileAccess* FileAccessJAndroid::create_jandroid() {
+
+ return memnew(FileAccessJAndroid);
+}
+
+Error FileAccessJAndroid::open(const String& p_path, int p_mode_flags) {
+
+ if (is_open())
+ close();
+
+ String path=fix_path(p_path).simplify_path();
+ if (path.begins_with("/"))
+ path=path.substr(1,path.length());
+ else if (path.begins_with("res://"))
+ path=path.substr(6,path.length());
+
+ //OS::get_singleton()->print("env: %p, io %p, fo: %p\n",env,io,_file_open);
+
+ jstring js = env->NewStringUTF(path.utf8().get_data());
+ int res = env->CallIntMethod(io,_file_open,js,p_mode_flags&WRITE?true:false);
+
+ if (res<=0)
+ return ERR_FILE_CANT_OPEN;
+ id=res;
+
+
+ return OK;
+}
+
+void FileAccessJAndroid::close() {
+
+ if (io==0)
+ return;
+
+ env->CallVoidMethod(io,_file_close,id);
+ id=0;
+
+}
+bool FileAccessJAndroid::is_open() const {
+
+ return id!=0;
+}
+
+void FileAccessJAndroid::seek(size_t p_position) {
+
+ ERR_FAIL_COND(!is_open());
+ env->CallVoidMethod(io,_file_seek,id,p_position);
+}
+void FileAccessJAndroid::seek_end(int64_t p_position) {
+
+ ERR_FAIL_COND(!is_open());
+
+ seek(get_len());
+
+}
+size_t FileAccessJAndroid::get_pos() const {
+
+ ERR_FAIL_COND_V(!is_open(),0);
+ return env->CallIntMethod(io,_file_tell,id);
+
+}
+size_t FileAccessJAndroid::get_len() const {
+
+ ERR_FAIL_COND_V(!is_open(),0);
+ return env->CallIntMethod(io,_file_get_size,id);
+
+
+}
+
+bool FileAccessJAndroid::eof_reached() const {
+
+ ERR_FAIL_COND_V(!is_open(),0);
+ return env->CallIntMethod(io,_file_eof,id);
+
+}
+
+uint8_t FileAccessJAndroid::get_8() const {
+
+ ERR_FAIL_COND_V(!is_open(),0);
+ uint8_t byte;
+ get_buffer(&byte,1);
+ return byte;
+}
+int FileAccessJAndroid::get_buffer(uint8_t *p_dst, int p_length) const {
+
+ ERR_FAIL_COND_V(!is_open(),0);
+ if (p_length==0)
+ return 0;
+
+ jbyteArray jca = (jbyteArray)env->CallObjectMethod(io,_file_read,id,p_length);
+
+ int len = env->GetArrayLength(jca);
+ env->GetByteArrayRegion(jca,0,len,(jbyte*)p_dst);
+ env->DeleteLocalRef((jobject)jca);
+
+ return len;
+
+}
+
+Error FileAccessJAndroid::get_error() const {
+
+ if (eof_reached())
+ return ERR_FILE_EOF;
+ return OK;
+}
+
+void FileAccessJAndroid::store_8(uint8_t p_dest) {
+
+
+}
+
+bool FileAccessJAndroid::file_exists(const String& p_path) {
+
+ jstring js = env->NewStringUTF(p_path.utf8().get_data());
+ int res = env->CallIntMethod(io,_file_open,js,false);
+ if (res<=0)
+ return false;
+ env->CallVoidMethod(io,_file_close,res);
+ return true;
+
+}
+
+
+void FileAccessJAndroid::setup( JNIEnv *p_env, jobject p_io) {
+
+ io=p_io;
+ env=p_env;
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP5");
+
+ jclass c = env->GetObjectClass(io);
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP6");
+ cls=(jclass)env->NewGlobalRef(c);
+
+ _file_open = env->GetMethodID(cls, "file_open", "(Ljava/lang/String;Z)I");
+ if(_file_open != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_open ok!!");
+ }
+ _file_get_size = env->GetMethodID(cls, "file_get_size", "(I)I");
+ if(_file_get_size != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_get_size ok!!");
+ }
+ _file_tell = env->GetMethodID(cls, "file_tell", "(I)I");
+ if(_file_tell != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_tell ok!!");
+ }
+ _file_eof = env->GetMethodID(cls, "file_eof", "(I)Z");
+
+ if(_file_eof != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_eof ok!!");
+ }
+ _file_seek = env->GetMethodID(cls, "file_seek", "(II)V");
+ if(_file_seek != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_seek ok!!");
+ }
+ _file_read = env->GetMethodID(cls, "file_read", "(II)[B");
+ if(_file_read != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_read ok!!");
+ }
+ _file_close = env->GetMethodID(cls, "file_close", "(I)V");
+ if(_file_close != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_close ok!!");
+ }
+
+// (*env)->CallVoidMethod(env,obj,aMethodID, myvar);
+}
+
+
+FileAccessJAndroid::FileAccessJAndroid()
+{
+
+ id=0;
+}
+
+FileAccessJAndroid::~FileAccessJAndroid()
+{
+
+ if (is_open())
+ close();
+}
+
+
diff --git a/platform/android/.old/file_access_jandroid.h b/platform/android/.old/file_access_jandroid.h
new file mode 100644
index 0000000000..7b432fc4fd
--- /dev/null
+++ b/platform/android/.old/file_access_jandroid.h
@@ -0,0 +1,56 @@
+#ifndef FILE_ACCESS_JANDROID_H
+#define FILE_ACCESS_JANDROID_H
+
+#include "java_glue.h"
+#include "os/file_access.h"
+class FileAccessJAndroid : public FileAccess {
+
+ static jobject io;
+ static jclass cls;
+
+ static jmethodID _file_open;
+ static jmethodID _file_get_size;
+ static jmethodID _file_seek;
+ static jmethodID _file_tell;
+ static jmethodID _file_eof;
+ static jmethodID _file_read;
+ static jmethodID _file_close;
+
+
+ static JNIEnv * env;
+
+ int id;
+ static FileAccess* create_jandroid();
+
+
+public:
+
+ virtual Error open(const String& p_path, int p_mode_flags); ///< open a file
+ virtual void close(); ///< close a file
+ virtual bool is_open() const; ///< true when file is open
+
+ virtual void seek(size_t p_position); ///< seek to a given position
+ virtual void seek_end(int64_t p_position=0); ///< seek from the end of file
+ virtual size_t get_pos() const; ///< get position in the file
+ virtual size_t get_len() const; ///< get size of the file
+
+ virtual bool eof_reached() const; ///< reading passed EOF
+
+ virtual uint8_t get_8() const; ///< get a byte
+ virtual int get_buffer(uint8_t *p_dst, int p_length) const;
+
+ virtual Error get_error() const; ///< get last error
+
+ virtual void store_8(uint8_t p_dest); ///< store a byte
+
+ virtual bool file_exists(const String& p_path); ///< return true if a file exists
+
+ static void make_default();
+
+ static void setup( JNIEnv *env, jobject io);
+ static void update_env( JNIEnv *p_env) { env=p_env; }
+ FileAccessJAndroid();
+ ~FileAccessJAndroid();
+};
+
+#endif // FILE_ACCESS_JANDROID_H
diff --git a/platform/android/.old/gdb.setup.base b/platform/android/.old/gdb.setup.base
new file mode 100644
index 0000000000..a622b1caf6
--- /dev/null
+++ b/platform/android/.old/gdb.setup.base
@@ -0,0 +1,3 @@
+set solib-search-path .
+directory ../..
+file app_process
diff --git a/platform/android/.old/java/AndroidManifest.xml b/platform/android/.old/java/AndroidManifest.xml
new file mode 100644
index 0000000000..c05a681fe3
--- /dev/null
+++ b/platform/android/.old/java/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.godot"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <application android:label="@string/godot" android:icon="@drawable/icon">
+ <activity android:name="Godot"
+ android:label="@string/godot"
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+ android:launchMode="singleTask"
+ android:configChanges="orientation|keyboardHidden">
+
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+ <uses-feature android:glEsVersion="0x00020000"/>
+ <uses-sdk android:minSdkVersion="8"/>
+
+</manifest>
diff --git a/platform/android/.old/java/build.properties b/platform/android/.old/java/build.properties
new file mode 100644
index 0000000000..ee52d86d94
--- /dev/null
+++ b/platform/android/.old/java/build.properties
@@ -0,0 +1,17 @@
+# This file is used to override default values used by the Ant build system.
+#
+# This file must be checked in Version Control Systems, as it is
+# integral to the build system of your project.
+
+# This file is only used by the Ant script.
+
+# You can use this to override default values such as
+# 'source.dir' for the location of your java source folder and
+# 'out.dir' for the location of your output folder.
+
+# You can also use it define how the release builds are signed by declaring
+# the following properties:
+# 'key.store' for the location of your keystore and
+# 'key.alias' for the name of the key to use.
+# The password will be asked during the build when you use the 'release' target.
+
diff --git a/platform/android/.old/java/build.xml b/platform/android/.old/java/build.xml
new file mode 100644
index 0000000000..6dc5eb874c
--- /dev/null
+++ b/platform/android/.old/java/build.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="Godot" default="help">
+
+<!-- The local.properties file is created and updated by the 'android'
+ tool.
+ It contains the path to the SDK. It should *NOT* be checked into
+ Version Control Systems. -->
+ <property file="local.properties" />
+ <property name="asset-dir" value="assets" />
+ <!-- The build.properties file can be created by you and is never touched
+ by the 'android' tool. This is the place to change some of the
+ default property values used by the Ant rules.
+ Here are some properties you may want to change/update:
+
+ source.dir
+ The name of the source directory. Default is 'src'.
+ out.dir
+ The name of the output directory. Default is 'bin'.
+
+ Properties related to the SDK location or the project target should
+ be updated using the 'android' tool with the 'update' action.
+
+ This file is an integral part of the build system for your
+ application and should be checked into Version Control Systems.
+
+ -->
+ <property file="build.properties" />
+
+ <!-- The default.properties file is created and updated by the 'android'
+ tool, as well as ADT.
+ This file is an integral part of the build system for your
+ application and should be checked into Version Control Systems. -->
+ <property file="default.properties" />
+
+
+ <!-- Required pre-setup import -->
+ <import file="${sdk.dir}/tools/ant/pre_setup.xml" />
+
+
+<!-- extension targets. Uncomment the ones where you want to do custom work
+ in between standard targets -->
+<!--
+ <target name="-pre-build">
+ </target>
+ <target name="-pre-compile">
+ </target>
+
+ [This is typically used for code obfuscation.
+ Compiled code location: ${out.classes.absolute.dir}
+ If this is not done in place, override ${out.dex.input.absolute.dir}]
+ <target name="-post-compile">
+ </target>
+-->
+
+ <!-- Execute the Android Setup task that will setup some properties
+ specific to the target, and import the build rules files.
+
+ The rules file is imported from
+ <SDK>/tools/ant/
+ Depending on the project type it can be either:
+ - main_rules.xml
+ - lib_rules.xml
+ - test_rules.xml
+
+ To customize existing targets, there are two options:
+ - Customize only one target:
+ - copy/paste the target into this file, *before* the
+ <setup> task.
+ - customize it to your needs.
+ - Customize the whole script.
+ - copy/paste the content of the rules files (minus the top node)
+ into this file, *after* the <setup> task
+ - disable the import of the rules by changing the setup task
+ below to <setup import="false" />.
+ - customize to your needs.
+ -->
+ <setup />
+
+</project>
diff --git a/platform/android/.old/java/default.properties b/platform/android/.old/java/default.properties
new file mode 100644
index 0000000000..e2e8061f26
--- /dev/null
+++ b/platform/android/.old/java/default.properties
@@ -0,0 +1,11 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-8
diff --git a/platform/android/.old/java/libs/armeabi/gdbserver b/platform/android/.old/java/libs/armeabi/gdbserver
new file mode 100755
index 0000000000..39634a8147
--- /dev/null
+++ b/platform/android/.old/java/libs/armeabi/gdbserver
Binary files differ
diff --git a/platform/android/.old/java/local.properties b/platform/android/.old/java/local.properties
new file mode 100644
index 0000000000..18e2b6b0cb
--- /dev/null
+++ b/platform/android/.old/java/local.properties
@@ -0,0 +1,10 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must *NOT* be checked in Version Control Systems,
+# as it contains information specific to your local configuration.
+
+# location of the SDK. This is only used by Ant
+# For customization when using a Version Control System, please read the
+# header note.
+sdk.dir=/home/red/bin/android-sdk-linux_x86
diff --git a/platform/android/.old/java/proguard.cfg b/platform/android/.old/java/proguard.cfg
new file mode 100644
index 0000000000..12dd0392c0
--- /dev/null
+++ b/platform/android/.old/java/proguard.cfg
@@ -0,0 +1,36 @@
+-optimizationpasses 5
+-dontusemixedcaseclassnames
+-dontskipnonpubliclibraryclasses
+-dontpreverify
+-verbose
+-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
+
+-keep public class * extends android.app.Activity
+-keep public class * extends android.app.Application
+-keep public class * extends android.app.Service
+-keep public class * extends android.content.BroadcastReceiver
+-keep public class * extends android.content.ContentProvider
+-keep public class * extends android.app.backup.BackupAgentHelper
+-keep public class * extends android.preference.Preference
+-keep public class com.android.vending.licensing.ILicensingService
+
+-keepclasseswithmembernames class * {
+ native <methods>;
+}
+
+-keepclasseswithmembernames class * {
+ public <init>(android.content.Context, android.util.AttributeSet);
+}
+
+-keepclasseswithmembernames class * {
+ public <init>(android.content.Context, android.util.AttributeSet, int);
+}
+
+-keepclassmembers enum * {
+ public static **[] values();
+ public static ** valueOf(java.lang.String);
+}
+
+-keep class * implements android.os.Parcelable {
+ public static final android.os.Parcelable$Creator *;
+}
diff --git a/platform/android/.old/java/res/drawable-hdpi/icon.png b/platform/android/.old/java/res/drawable-hdpi/icon.png
new file mode 100644
index 0000000000..8074c4c571
--- /dev/null
+++ b/platform/android/.old/java/res/drawable-hdpi/icon.png
Binary files differ
diff --git a/platform/android/.old/java/res/drawable-ldpi/icon.png b/platform/android/.old/java/res/drawable-ldpi/icon.png
new file mode 100644
index 0000000000..1095584ec2
--- /dev/null
+++ b/platform/android/.old/java/res/drawable-ldpi/icon.png
Binary files differ
diff --git a/platform/android/.old/java/res/drawable-mdpi/icon.png b/platform/android/.old/java/res/drawable-mdpi/icon.png
new file mode 100644
index 0000000000..a07c69fa5a
--- /dev/null
+++ b/platform/android/.old/java/res/drawable-mdpi/icon.png
Binary files differ
diff --git a/platform/android/.old/java/res/values/strings.xml b/platform/android/.old/java/res/values/strings.xml
new file mode 100644
index 0000000000..f92332ad4c
--- /dev/null
+++ b/platform/android/.old/java/res/values/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot">Godot</string>
+</resources>
diff --git a/platform/android/.old/java/src/com/android/godot/Godot.java b/platform/android/.old/java/src/com/android/godot/Godot.java
new file mode 100644
index 0000000000..475caf3362
--- /dev/null
+++ b/platform/android/.old/java/src/com/android/godot/Godot.java
@@ -0,0 +1,85 @@
+package com.android.godot;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.MotionEvent;
+
+public class Godot extends Activity
+{
+
+
+ GodotView mView;
+
+ static public GodotIO io;
+
+
+ @Override protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ io = new GodotIO(getAssets());
+ GodotLib.io=io;
+ mView = new GodotView(getApplication(),io);
+ setContentView(mView);
+ }
+
+ @Override protected void onPause() {
+ super.onPause();
+ mView.onPause();
+ }
+
+ @Override protected void onResume() {
+ super.onResume();
+ mView.onResume();
+ }
+
+ @Override public boolean dispatchTouchEvent (MotionEvent event) {
+
+ super.onTouchEvent(event);
+ int evcount=event.getPointerCount();
+ if (evcount==0)
+ return true;
+
+ int[] arr = new int[event.getPointerCount()*3];
+
+ for(int i=0;i<event.getPointerCount();i++) {
+
+ arr[i*3+0]=(int)event.getPointerId(i);
+ arr[i*3+1]=(int)event.getX(i);
+ arr[i*3+2]=(int)event.getY(i);
+ }
+
+ //System.out.printf("gaction: %d\n",event.getAction());
+ switch(event.getAction()&MotionEvent.ACTION_MASK) {
+
+ case MotionEvent.ACTION_DOWN: {
+ GodotLib.touch(0,0,evcount,arr);
+ //System.out.printf("action down at: %f,%f\n", event.getX(),event.getY());
+ } break;
+ case MotionEvent.ACTION_MOVE: {
+ GodotLib.touch(1,0,evcount,arr);
+ //for(int i=0;i<event.getPointerCount();i++) {
+ // System.out.printf("%d - moved to: %f,%f\n",i, event.getX(i),event.getY(i));
+ //}
+ } break;
+ case MotionEvent.ACTION_POINTER_UP: {
+ int pointer_idx = event.getActionIndex();
+ GodotLib.touch(4,pointer_idx,evcount,arr);
+ //System.out.printf("%d - s.up at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
+ } break;
+ case MotionEvent.ACTION_POINTER_DOWN: {
+ int pointer_idx = event.getActionIndex();
+ GodotLib.touch(3,pointer_idx,evcount,arr);
+ //System.out.printf("%d - s.down at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
+ } break;
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP: {
+ GodotLib.touch(2,0,evcount,arr);
+ //for(int i=0;i<event.getPointerCount();i++) {
+ // System.out.printf("%d - up! %f,%f\n",i, event.getX(i),event.getY(i));
+ //}
+ } break;
+
+ }
+ return true;
+ }
+
+}
diff --git a/platform/android/.old/java/src/com/android/godot/GodotIO.java b/platform/android/.old/java/src/com/android/godot/GodotIO.java
new file mode 100644
index 0000000000..a673f79b8d
--- /dev/null
+++ b/platform/android/.old/java/src/com/android/godot/GodotIO.java
@@ -0,0 +1,277 @@
+
+package com.android.godot;
+import java.util.HashMap;
+
+import android.content.res.AssetManager;
+import java.io.InputStream;
+import java.io.IOException;
+
+// Wrapper for native library
+
+public class GodotIO {
+
+
+ AssetManager am;
+
+
+ /// FILES
+
+ public int last_file_id=1;
+
+ class AssetData {
+
+
+ public boolean eof=false;
+ public String path;
+ public InputStream is;
+ public int len;
+ public int pos;
+ }
+
+
+ HashMap<Integer,AssetData> streams;
+
+
+ public int file_open(String path,boolean write) {
+
+ System.out.printf("file_open: Attempt to Open %s\n",path);
+
+ if (write)
+ return -1;
+
+
+ AssetData ad = new AssetData();
+
+ try {
+ ad.is = am.open(path);
+
+ } catch (Exception e) {
+
+ System.out.printf("Exception on file_open: %s\n",e);
+ return -1;
+ }
+
+ try {
+ ad.len=ad.is.available();
+ } catch (Exception e) {
+
+ System.out.printf("Exception availabling on file_open: %s\n",e);
+ return -1;
+ }
+
+ ad.path=path;
+ ad.pos=0;
+ ++last_file_id;
+ streams.put(last_file_id,ad);
+
+ return last_file_id;
+ }
+ public int file_get_size(int id) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_get_size: Invalid file id: %d\n",id);
+ return -1;
+ }
+
+ return streams.get(id).len;
+
+ }
+ public void file_seek(int id,int bytes) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_get_size: Invalid file id: %d\n",id);
+ return;
+ }
+ //seek sucks
+ AssetData ad = streams.get(id);
+ if (bytes>ad.len)
+ bytes=ad.len;
+ if (bytes<0)
+ bytes=0;
+
+ try {
+
+ if (bytes > (int)ad.pos) {
+ int todo=bytes-(int)ad.pos;
+ while(todo>0) {
+ todo-=ad.is.skip(todo);
+ }
+ ad.pos=bytes;
+ } else if (bytes<(int)ad.pos) {
+
+ ad.is=am.open(ad.path);
+
+ ad.pos=bytes;
+ int todo=bytes;
+ while(todo>0) {
+ todo-=ad.is.skip(todo);
+ }
+ }
+
+ ad.eof=false;
+ } catch (IOException e) {
+
+ System.out.printf("Exception on file_seek: %s\n",e);
+ return;
+ }
+
+
+ }
+
+ public int file_tell(int id) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_read: Can't tell eof for invalid file id: %d\n",id);
+ return 0;
+ }
+
+ AssetData ad = streams.get(id);
+ return ad.pos;
+ }
+ public boolean file_eof(int id) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_read: Can't check eof for invalid file id: %d\n",id);
+ return false;
+ }
+
+ AssetData ad = streams.get(id);
+ return ad.eof;
+ }
+
+ public byte[] file_read(int id, int bytes) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_read: Can't read invalid file id: %d\n",id);
+ return new byte[0];
+ }
+
+
+ AssetData ad = streams.get(id);
+
+ if (ad.pos + bytes > ad.len) {
+
+ bytes=ad.len-ad.pos;
+ ad.eof=true;
+ }
+
+
+ if (bytes==0) {
+
+ return new byte[0];
+ }
+
+
+
+ byte[] buf1=new byte[bytes];
+ int r=0;
+ try {
+ r = ad.is.read(buf1);
+ } catch (IOException e) {
+
+ System.out.printf("Exception on file_read: %s\n",e);
+ return new byte[bytes];
+ }
+
+ if (r==0) {
+ return new byte[0];
+ }
+
+ ad.pos+=r;
+
+ if (r<bytes) {
+
+ byte[] buf2=new byte[r];
+ for(int i=0;i<r;i++)
+ buf2[i]=buf1[i];
+ return buf2;
+ } else {
+
+ return buf1;
+ }
+
+ }
+
+ public void file_close(int id) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_close: Can't close invalid file id: %d\n",id);
+ return;
+ }
+
+ streams.remove(id);
+
+ }
+
+
+ /// DIRECTORIES
+
+
+ class AssetDir {
+
+ public String[] files;
+ public int current;
+ }
+
+ public int last_dir_id=1;
+
+ HashMap<Integer,AssetDir> dirs;
+
+ public int dir_open(String path) {
+
+ AssetDir ad = new AssetDir();
+ ad.current=0;
+
+ try {
+ ad.files = am.list(path);
+ } catch (IOException e) {
+
+ System.out.printf("Exception on dir_open: %s\n",e);
+ return -1;
+ }
+
+ ++last_dir_id;
+ dirs.put(last_dir_id,ad);
+
+ return last_dir_id;
+
+ }
+
+ public String dir_next(int id) {
+
+ if (!dirs.containsKey(id)) {
+ System.out.printf("dir_next: invalid dir id: %d\n",id);
+ return "";
+ }
+
+ AssetDir ad = dirs.get(id);
+ if (ad.current>=ad.files.length)
+ return "";
+ String r = ad.files[ad.current];
+ ad.current++;
+ return r;
+
+ }
+
+ public void dir_close(int id) {
+
+ if (!dirs.containsKey(id)) {
+ System.out.printf("dir_close: invalid dir id: %d\n",id);
+ return;
+ }
+
+ dirs.remove(id);
+ }
+
+
+ GodotIO(AssetManager p_am) {
+
+ am=p_am;
+ streams=new HashMap<Integer,AssetData>();
+ dirs=new HashMap<Integer,AssetDir>();
+
+
+ }
+
+
+}
diff --git a/platform/android/.old/java/src/com/android/godot/GodotLib.java b/platform/android/.old/java/src/com/android/godot/GodotLib.java
new file mode 100644
index 0000000000..2ef49a5222
--- /dev/null
+++ b/platform/android/.old/java/src/com/android/godot/GodotLib.java
@@ -0,0 +1,22 @@
+package com.android.godot;
+
+// Wrapper for native library
+
+public class GodotLib {
+
+
+ public static GodotIO io;
+
+ static {
+ System.loadLibrary("godot_android");
+ }
+
+ /**
+ * @param width the current view width
+ * @param height the current view height
+ */
+
+ public static native void init(int width, int height);
+ public static native void step();
+ public static native void touch(int what,int pointer,int howmany, int[] arr);
+}
diff --git a/platform/android/.old/java/src/com/android/godot/GodotView.java b/platform/android/.old/java/src/com/android/godot/GodotView.java
new file mode 100644
index 0000000000..c5eb3d17ad
--- /dev/null
+++ b/platform/android/.old/java/src/com/android/godot/GodotView.java
@@ -0,0 +1,319 @@
+package com.android.godot;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.content.ContextWrapper;
+
+import java.io.File;
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * A simple GLSurfaceView sub-class that demonstrate how to perform
+ * OpenGL ES 2.0 rendering into a GL Surface. Note the following important
+ * details:
+ *
+ * - The class must use a custom context factory to enable 2.0 rendering.
+ * See ContextFactory class definition below.
+ *
+ * - The class must use a custom EGLConfigChooser to be able to select
+ * an EGLConfig that supports 2.0. This is done by providing a config
+ * specification to eglChooseConfig() that has the attribute
+ * EGL10.ELG_RENDERABLE_TYPE containing the EGL_OPENGL_ES2_BIT flag
+ * set. See ConfigChooser class definition below.
+ *
+ * - The class must select the surface's format, then choose an EGLConfig
+ * that matches it exactly (with regards to red/green/blue/alpha channels
+ * bit depths). Failure to do so would result in an EGL_BAD_MATCH error.
+ */
+class GodotView extends GLSurfaceView {
+ private static String TAG = "GodotView";
+ private static final boolean DEBUG = false;
+ private static Context ctx;
+
+ private static GodotIO io;
+
+ public GodotView(Context context,GodotIO p_io) {
+ super(context);
+ ctx=context;
+ io=p_io;
+
+ init(false, 0, 0);
+ }
+
+ public GodotView(Context context, boolean translucent, int depth, int stencil) {
+ super(context);
+ init(translucent, depth, stencil);
+ }
+
+ private void init(boolean translucent, int depth, int stencil) {
+
+ /* By default, GLSurfaceView() creates a RGB_565 opaque surface.
+ * If we want a translucent one, we should change the surface's
+ * format here, using PixelFormat.TRANSLUCENT for GL Surfaces
+ * is interpreted as any 32-bit surface with alpha by SurfaceFlinger.
+ */
+ if (translucent) {
+ this.getHolder().setFormat(PixelFormat.TRANSLUCENT);
+ }
+
+ /* Setup the context factory for 2.0 rendering.
+ * See ContextFactory class definition below
+ */
+ setEGLContextFactory(new ContextFactory());
+
+ /* We need to choose an EGLConfig that matches the format of
+ * our surface exactly. This is going to be done in our
+ * custom config chooser. See ConfigChooser class definition
+ * below.
+ */
+ setEGLConfigChooser( translucent ?
+ new ConfigChooser(8, 8, 8, 8, depth, stencil) :
+ new ConfigChooser(5, 6, 5, 0, depth, stencil) );
+
+ /* Set the renderer responsible for frame rendering */
+ setRenderer(new Renderer());
+ }
+
+ private static class ContextFactory implements GLSurfaceView.EGLContextFactory {
+ private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+ public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {
+ Log.w(TAG, "creating OpenGL ES 2.0 context");
+ checkEglError("Before eglCreateContext", egl);
+ int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
+ EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
+ checkEglError("After eglCreateContext", egl);
+ return context;
+ }
+
+ public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {
+ egl.eglDestroyContext(display, context);
+ }
+ }
+
+ private static void checkEglError(String prompt, EGL10 egl) {
+ int error;
+ while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) {
+ Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error));
+ }
+ }
+
+ private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser {
+
+ public ConfigChooser(int r, int g, int b, int a, int depth, int stencil) {
+ mRedSize = r;
+ mGreenSize = g;
+ mBlueSize = b;
+ mAlphaSize = a;
+ mDepthSize = depth;
+ mStencilSize = stencil;
+ }
+
+ /* This EGL config specification is used to specify 2.0 rendering.
+ * We use a minimum size of 4 bits for red/green/blue, but will
+ * perform actual matching in chooseConfig() below.
+ */
+ private static int EGL_OPENGL_ES2_BIT = 4;
+ private static int[] s_configAttribs2 =
+ {
+ EGL10.EGL_RED_SIZE, 4,
+ EGL10.EGL_GREEN_SIZE, 4,
+ EGL10.EGL_BLUE_SIZE, 4,
+ EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL10.EGL_NONE
+ };
+
+ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
+
+ /* Get the number of minimally matching EGL configurations
+ */
+ int[] num_config = new int[1];
+ egl.eglChooseConfig(display, s_configAttribs2, null, 0, num_config);
+
+ int numConfigs = num_config[0];
+
+ if (numConfigs <= 0) {
+ throw new IllegalArgumentException("No configs match configSpec");
+ }
+
+ /* Allocate then read the array of minimally matching EGL configs
+ */
+ EGLConfig[] configs = new EGLConfig[numConfigs];
+ egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs, num_config);
+
+ if (DEBUG) {
+ printConfigs(egl, display, configs);
+ }
+ /* Now return the "best" one
+ */
+ return chooseConfig(egl, display, configs);
+ }
+
+ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
+ EGLConfig[] configs) {
+ for(EGLConfig config : configs) {
+ int d = findConfigAttrib(egl, display, config,
+ EGL10.EGL_DEPTH_SIZE, 0);
+ int s = findConfigAttrib(egl, display, config,
+ EGL10.EGL_STENCIL_SIZE, 0);
+
+ // We need at least mDepthSize and mStencilSize bits
+ if (d < mDepthSize || s < mStencilSize)
+ continue;
+
+ // We want an *exact* match for red/green/blue/alpha
+ int r = findConfigAttrib(egl, display, config,
+ EGL10.EGL_RED_SIZE, 0);
+ int g = findConfigAttrib(egl, display, config,
+ EGL10.EGL_GREEN_SIZE, 0);
+ int b = findConfigAttrib(egl, display, config,
+ EGL10.EGL_BLUE_SIZE, 0);
+ int a = findConfigAttrib(egl, display, config,
+ EGL10.EGL_ALPHA_SIZE, 0);
+
+ if (r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize)
+ return config;
+ }
+ return null;
+ }
+
+ private int findConfigAttrib(EGL10 egl, EGLDisplay display,
+ EGLConfig config, int attribute, int defaultValue) {
+
+ if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
+ return mValue[0];
+ }
+ return defaultValue;
+ }
+
+ private void printConfigs(EGL10 egl, EGLDisplay display,
+ EGLConfig[] configs) {
+ int numConfigs = configs.length;
+ Log.w(TAG, String.format("%d configurations", numConfigs));
+ for (int i = 0; i < numConfigs; i++) {
+ Log.w(TAG, String.format("Configuration %d:\n", i));
+ printConfig(egl, display, configs[i]);
+ }
+ }
+
+ private void printConfig(EGL10 egl, EGLDisplay display,
+ EGLConfig config) {
+ int[] attributes = {
+ EGL10.EGL_BUFFER_SIZE,
+ EGL10.EGL_ALPHA_SIZE,
+ EGL10.EGL_BLUE_SIZE,
+ EGL10.EGL_GREEN_SIZE,
+ EGL10.EGL_RED_SIZE,
+ EGL10.EGL_DEPTH_SIZE,
+ EGL10.EGL_STENCIL_SIZE,
+ EGL10.EGL_CONFIG_CAVEAT,
+ EGL10.EGL_CONFIG_ID,
+ EGL10.EGL_LEVEL,
+ EGL10.EGL_MAX_PBUFFER_HEIGHT,
+ EGL10.EGL_MAX_PBUFFER_PIXELS,
+ EGL10.EGL_MAX_PBUFFER_WIDTH,
+ EGL10.EGL_NATIVE_RENDERABLE,
+ EGL10.EGL_NATIVE_VISUAL_ID,
+ EGL10.EGL_NATIVE_VISUAL_TYPE,
+ 0x3030, // EGL10.EGL_PRESERVED_RESOURCES,
+ EGL10.EGL_SAMPLES,
+ EGL10.EGL_SAMPLE_BUFFERS,
+ EGL10.EGL_SURFACE_TYPE,
+ EGL10.EGL_TRANSPARENT_TYPE,
+ EGL10.EGL_TRANSPARENT_RED_VALUE,
+ EGL10.EGL_TRANSPARENT_GREEN_VALUE,
+ EGL10.EGL_TRANSPARENT_BLUE_VALUE,
+ 0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB,
+ 0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA,
+ 0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL,
+ 0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL,
+ EGL10.EGL_LUMINANCE_SIZE,
+ EGL10.EGL_ALPHA_MASK_SIZE,
+ EGL10.EGL_COLOR_BUFFER_TYPE,
+ EGL10.EGL_RENDERABLE_TYPE,
+ 0x3042 // EGL10.EGL_CONFORMANT
+ };
+ String[] names = {
+ "EGL_BUFFER_SIZE",
+ "EGL_ALPHA_SIZE",
+ "EGL_BLUE_SIZE",
+ "EGL_GREEN_SIZE",
+ "EGL_RED_SIZE",
+ "EGL_DEPTH_SIZE",
+ "EGL_STENCIL_SIZE",
+ "EGL_CONFIG_CAVEAT",
+ "EGL_CONFIG_ID",
+ "EGL_LEVEL",
+ "EGL_MAX_PBUFFER_HEIGHT",
+ "EGL_MAX_PBUFFER_PIXELS",
+ "EGL_MAX_PBUFFER_WIDTH",
+ "EGL_NATIVE_RENDERABLE",
+ "EGL_NATIVE_VISUAL_ID",
+ "EGL_NATIVE_VISUAL_TYPE",
+ "EGL_PRESERVED_RESOURCES",
+ "EGL_SAMPLES",
+ "EGL_SAMPLE_BUFFERS",
+ "EGL_SURFACE_TYPE",
+ "EGL_TRANSPARENT_TYPE",
+ "EGL_TRANSPARENT_RED_VALUE",
+ "EGL_TRANSPARENT_GREEN_VALUE",
+ "EGL_TRANSPARENT_BLUE_VALUE",
+ "EGL_BIND_TO_TEXTURE_RGB",
+ "EGL_BIND_TO_TEXTURE_RGBA",
+ "EGL_MIN_SWAP_INTERVAL",
+ "EGL_MAX_SWAP_INTERVAL",
+ "EGL_LUMINANCE_SIZE",
+ "EGL_ALPHA_MASK_SIZE",
+ "EGL_COLOR_BUFFER_TYPE",
+ "EGL_RENDERABLE_TYPE",
+ "EGL_CONFORMANT"
+ };
+ int[] value = new int[1];
+ for (int i = 0; i < attributes.length; i++) {
+ int attribute = attributes[i];
+ String name = names[i];
+ if ( egl.eglGetConfigAttrib(display, config, attribute, value)) {
+ Log.w(TAG, String.format(" %s: %d\n", name, value[0]));
+ } else {
+ // Log.w(TAG, String.format(" %s: failed\n", name));
+ while (egl.eglGetError() != EGL10.EGL_SUCCESS);
+ }
+ }
+ }
+
+ // Subclasses can adjust these values:
+ protected int mRedSize;
+ protected int mGreenSize;
+ protected int mBlueSize;
+ protected int mAlphaSize;
+ protected int mDepthSize;
+ protected int mStencilSize;
+ private int[] mValue = new int[1];
+ }
+
+ private static class Renderer implements GLSurfaceView.Renderer {
+
+
+ public void onDrawFrame(GL10 gl) {
+ GodotLib.step();
+ }
+
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+
+
+ System.out.printf("** CONTENT DIR %s\n",ctx.getFilesDir().getPath());
+ GodotLib.init(width, height);
+ }
+
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ // Do nothing.
+ }
+ }
+}
diff --git a/platform/android/.old/java_glue.cpp b/platform/android/.old/java_glue.cpp
new file mode 100644
index 0000000000..38dbcc104f
--- /dev/null
+++ b/platform/android/.old/java_glue.cpp
@@ -0,0 +1,181 @@
+#include "java_glue.h"
+#include "os_android.h"
+#include "main/main.h"
+#include <unistd.h>
+#include "file_access_jandroid.h"
+#include "dir_access_jandroid.h"
+
+static OS_Android *os_android=NULL;
+
+
+struct TST {
+
+ int a;
+ TST() {
+
+ a=5;
+ }
+};
+
+TST tst;
+
+struct JAndroidPointerEvent {
+
+ Vector<OS_Android::TouchPos> points;
+ int pointer;
+ int what;
+};
+
+static List<JAndroidPointerEvent> pointer_events;
+static bool initialized=false;
+static Mutex *input_mutex=NULL;
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_init(JNIEnv * env, jobject obj, jint width, jint height)
+{
+
+
+ if (initialized) // wtf
+ return;
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","**INIT EVENT! - %p\n",env);
+
+
+ initialized=true;
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","***************** HELLO FROM JNI!!!!!!!!");
+
+ {
+ //setup IO Object
+
+ jclass cls = env->FindClass("com/android/godot/Godot");
+ if (cls) {
+
+ cls=(jclass)env->NewGlobalRef(cls);
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******CLASS FOUND!!!");
+ }
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP2, %p",cls);
+ jfieldID fid = env->GetStaticFieldID(cls, "io", "Lcom/android/godot/GodotIO;");
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP3 %i",fid);
+ jobject ob = env->GetStaticObjectField(cls,fid);
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP4, %p",ob);
+ jobject gob = env->NewGlobalRef(ob);
+
+
+ FileAccessJAndroid::setup(env,gob);
+ DirAccessJAndroid::setup(env,gob);
+ }
+
+
+
+ os_android = new OS_Android(width,height);
+
+ char wd[500];
+ getcwd(wd,500);
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","test construction %i\n",tst.a);
+ __android_log_print(ANDROID_LOG_INFO,"godot","running from dir %s\n",wd);
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","**SETUP");
+
+
+
+#if 0
+ char *args[]={"-test","render",NULL};
+ __android_log_print(ANDROID_LOG_INFO,"godot","pre asdasd setup...");
+ Error err = Main::setup("apk",2,args);
+#else
+ Error err = Main::setup("apk",0,NULL);
+#endif
+ if (err!=OK) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*****UNABLE TO SETUP");
+
+ return; //should exit instead and print the error
+ }
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","**START");
+
+
+ if (!Main::start()) {
+
+ return; //should exit instead and print the error
+ }
+ input_mutex=Mutex::create();
+
+ os_android->main_loop_begin();
+
+
+}
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_step(JNIEnv * env, jobject obj)
+{
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","**STEP EVENT! - %p-%i\n",env,Thread::get_caller_ID());
+
+
+
+
+ {
+
+ FileAccessJAndroid::update_env(env);
+ DirAccessJAndroid::update_env(env);
+ }
+
+ input_mutex->lock();
+
+ while(pointer_events.size()) {
+
+ JAndroidPointerEvent jpe=pointer_events.front()->get();
+ os_android->process_touch(jpe.what,jpe.pointer,jpe.points);
+ pointer_events.pop_front();
+ }
+
+ input_mutex->unlock();
+
+
+ if (os_android->main_loop_iterate()==true) {
+
+ return; //should exit instead
+ }
+
+
+}
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_touch(JNIEnv * env, jobject obj, jint ev,jint pointer, jint count, jintArray positions) {
+
+
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","**TOUCH EVENT! - %p-%i\n",env,Thread::get_caller_ID());
+
+
+
+
+
+ Vector<OS_Android::TouchPos> points;
+ for(int i=0;i<count;i++) {
+
+ jint p[3];
+ env->GetIntArrayRegion(positions,i*3,3,p);
+ OS_Android::TouchPos tp;
+ tp.pos=Point2(p[1],p[2]);
+ tp.id=p[0];
+ points.push_back(tp);
+ }
+
+ JAndroidPointerEvent jpe;
+ jpe.pointer=pointer;
+ jpe.points=points;
+ jpe.what=ev;
+
+ input_mutex->lock();
+
+ pointer_events.push_back(jpe);
+
+ input_mutex->unlock();
+ //if (os_android)
+// os_android->process_touch(ev,pointer,points);
+
+}
+
+//Main::cleanup();
+
+//return os.get_exit_code();
diff --git a/platform/android/.old/java_glue.h b/platform/android/.old/java_glue.h
new file mode 100644
index 0000000000..9940af3d7d
--- /dev/null
+++ b/platform/android/.old/java_glue.h
@@ -0,0 +1,16 @@
+#ifndef JAVA_GLUE_H
+#define JAVA_GLUE_H
+
+#include <jni.h>
+#include <android/log.h>
+
+
+extern "C" {
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_init(JNIEnv * env, jobject obj, jint width, jint height);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_step(JNIEnv * env, jobject obj);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_touch(JNIEnv * env, jobject obj, jint ev,jint pointer, jint count, jintArray positions);
+};
+
+
+
+#endif // JAVA_GLUE_H
diff --git a/platform/android/.old/os_android.cpp b/platform/android/.old/os_android.cpp
new file mode 100644
index 0000000000..ecd87a3af9
--- /dev/null
+++ b/platform/android/.old/os_android.cpp
@@ -0,0 +1,426 @@
+
+#include "os_android.h"
+#include "java_glue.h"
+#include "drivers/gles2/rasterizer_gles2.h"
+#include "servers/visual/visual_server_raster.h"
+
+#include "file_access_jandroid.h"
+#include "dir_access_jandroid.h"
+#include "core/io/file_access_buffered_fa.h"
+#include "main/main.h"
+int OS_Android::get_video_driver_count() const {
+
+ return 1;
+}
+const char * OS_Android::get_video_driver_name(int p_driver) const {
+
+ return "GLES2";
+}
+
+OS::VideoMode OS_Android::get_default_video_mode() const {
+
+ return OS::VideoMode();
+}
+
+int OS_Android::get_audio_driver_count() const {
+
+ return 1;
+}
+const char * OS_Android::get_audio_driver_name(int p_driver) const {
+
+ return "Android";
+}
+
+void OS_Android::initialize_core() {
+
+ OS_Unix::initialize_core();
+ //FileAccessJAndroid::make_default();
+ DirAccessJAndroid::make_default();
+ FileAccessBufferedFA<FileAccessJAndroid>::make_default();
+
+
+}
+
+void OS_Android::initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver) {
+
+ AudioDriverManagerSW::add_driver(&audio_driver_android);
+
+ rasterizer = memnew( RasterizerGLES2 );
+ visual_server = memnew( VisualServerRaster(rasterizer) );
+ visual_server->init();
+ visual_server->cursor_set_visible(false, 0);
+
+ AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton();
+
+ if (AudioDriverManagerSW::get_driver(p_audio_driver)->init()!=OK) {
+
+ ERR_PRINT("Initializing audio failed.");
+ }
+
+ sample_manager = memnew( SampleManagerMallocSW );
+ audio_server = memnew( AudioServerSW(sample_manager) );
+
+ audio_server->set_mixer_params(AudioMixerSW::INTERPOLATION_LINEAR,false);
+ audio_server->init();
+
+ spatial_sound_server = memnew( SpatialSoundServerSW );
+ spatial_sound_server->init();
+
+ spatial_sound_2d_server = memnew( SpatialSound2DServerSW );
+ spatial_sound_2d_server->init();
+
+ //
+ physics_server = memnew( PhysicsServerSW );
+ physics_server->init();
+ physics_2d_server = memnew( Physics2DServerSW );
+ physics_2d_server->init();
+
+ input = memnew( InputDefault );
+
+
+}
+
+void OS_Android::set_main_loop( MainLoop * p_main_loop ) {
+
+
+
+ main_loop=p_main_loop;
+}
+
+void OS_Android::delete_main_loop() {
+
+ memdelete( main_loop );
+}
+
+void OS_Android::finalize() {
+
+ memdelete(input);
+
+}
+
+
+void OS_Android::vprint(const char* p_format, va_list p_list, bool p_stderr) {
+
+ __android_log_vprint(p_stderr?ANDROID_LOG_ERROR:ANDROID_LOG_INFO,"godot",p_format,p_list);
+}
+
+void OS_Android::print(const char *p_format, ... ) {
+
+ va_list argp;
+ va_start(argp, p_format);
+ __android_log_vprint(ANDROID_LOG_INFO,"godot",p_format,argp);
+ va_end(argp);
+
+}
+
+void OS_Android::alert(const String& p_alert) {
+
+ print("ALERT: %s\n",p_alert.utf8().get_data());
+}
+
+
+void OS_Android::set_mouse_show(bool p_show) {
+
+ //android has no mouse...
+}
+
+void OS_Android::set_mouse_grab(bool p_grab) {
+
+ //it really has no mouse...!
+}
+
+bool OS_Android::is_mouse_grab_enabled() const {
+
+ //*sigh* technology has evolved so much since i was a kid..
+ return false;
+}
+Point2 OS_Android::get_mouse_pos() const {
+
+ return Point2();
+}
+int OS_Android::get_mouse_button_state() const {
+
+ return 0;
+}
+void OS_Android::set_window_title(const String& p_title) {
+
+
+}
+
+//interesting byt not yet
+//void set_clipboard(const String& p_text);
+//String get_clipboard() const;
+
+void OS_Android::set_video_mode(const VideoMode& p_video_mode,int p_screen) {
+
+
+}
+
+OS::VideoMode OS_Android::get_video_mode(int p_screen) const {
+
+ return default_videomode;
+}
+void OS_Android::get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen) const {
+
+ p_list->push_back(default_videomode);
+}
+
+String OS_Android::get_name() {
+
+ return "Android";
+}
+
+MainLoop *OS_Android::get_main_loop() const {
+
+ return main_loop;
+}
+
+bool OS_Android::can_draw() const {
+
+ return true; //always?
+}
+
+void OS_Android::set_cursor_shape(CursorShape p_shape) {
+
+ //android really really really has no mouse.. how amazing..
+}
+
+void OS_Android::main_loop_begin() {
+
+ if (main_loop)
+ main_loop->init();
+}
+bool OS_Android::main_loop_iterate() {
+
+ if (!main_loop)
+ return false;
+ return Main::iteration();
+}
+
+void OS_Android::main_loop_end() {
+
+ if (main_loop)
+ main_loop->finish();
+
+}
+
+void OS_Android::process_touch(int p_what,int p_pointer, const Vector<TouchPos>& p_points) {
+
+
+
+ switch(p_what) {
+ case 0: { //gesture begin
+
+ if (touch.size()) {
+ //end all if exist
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_BUTTON;
+ ev.ID=++last_id;
+ ev.mouse_button.button_index=BUTTON_LEFT;
+ ev.mouse_button.button_mask=BUTTON_MASK_LEFT;
+ ev.mouse_button.pressed=false;
+ ev.mouse_button.x=touch[0].pos.x;
+ ev.mouse_button.y=touch[0].pos.y;
+ ev.mouse_button.global_x=touch[0].pos.x;
+ ev.mouse_button.global_y=touch[0].pos.y;
+ main_loop->input_event(ev);
+
+
+ for(int i=0;i<touch.size();i++) {
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_TOUCH;
+ ev.ID=++last_id;
+ ev.screen_touch.index=touch[i].id;
+ ev.screen_touch.pressed=false;
+ ev.screen_touch.x=touch[i].pos.x;
+ ev.screen_touch.y=touch[i].pos.y;
+ main_loop->input_event(ev);
+
+ }
+ }
+
+ touch.resize(p_points.size());
+ for(int i=0;i<p_points.size();i++) {
+ touch[i].id=p_points[i].id;
+ touch[i].pos=p_points[i].pos;
+ }
+
+ {
+ //send mouse
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_BUTTON;
+ ev.ID=++last_id;
+ ev.mouse_button.button_index=BUTTON_LEFT;
+ ev.mouse_button.button_mask=BUTTON_MASK_LEFT;
+ ev.mouse_button.pressed=true;
+ ev.mouse_button.x=touch[0].pos.x;
+ ev.mouse_button.y=touch[0].pos.y;
+ ev.mouse_button.global_x=touch[0].pos.x;
+ ev.mouse_button.global_y=touch[0].pos.y;
+ last_mouse=touch[0].pos;
+ main_loop->input_event(ev);
+ }
+
+
+ //send touch
+ for(int i=0;i<touch.size();i++) {
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_TOUCH;
+ ev.ID=++last_id;
+ ev.screen_touch.index=touch[i].id;
+ ev.screen_touch.pressed=true;
+ ev.screen_touch.x=touch[i].pos.x;
+ ev.screen_touch.y=touch[i].pos.y;
+ main_loop->input_event(ev);
+ }
+
+ } break;
+ case 1: { //motion
+
+
+ if (p_points.size()) {
+ //send mouse, should look for point 0?
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_MOTION;
+ ev.ID=++last_id;
+ ev.mouse_motion.button_mask=BUTTON_MASK_LEFT;
+ ev.mouse_motion.x=p_points[0].pos.x;
+ ev.mouse_motion.y=p_points[0].pos.y;
+ input->set_mouse_pos(Point2(ev.mouse_motion.x,ev.mouse_motion.y));
+ ev.mouse_motion.speed_x=input->get_mouse_speed().x;
+ ev.mouse_motion.speed_y=input->get_mouse_speed().y;
+ ev.mouse_motion.relative_x=p_points[0].pos.x-last_mouse.x;
+ ev.mouse_motion.relative_y=p_points[0].pos.y-last_mouse.y;
+ last_mouse=p_points[0].pos;
+ main_loop->input_event(ev);
+ }
+
+ ERR_FAIL_COND(touch.size()!=p_points.size());
+
+ for(int i=0;i<touch.size();i++) {
+
+ int idx=-1;
+ for(int j=0;j<p_points.size();j++) {
+
+ if (touch[i].id==p_points[j].id) {
+ idx=j;
+ break;
+ }
+
+ }
+
+ ERR_CONTINUE(idx==-1);
+
+ if (touch[i].pos==p_points[idx].pos)
+ continue; //no move unncesearily
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_DRAG;
+ ev.ID=++last_id;
+ ev.screen_drag.index=touch[i].id;
+ ev.screen_drag.x=p_points[idx].pos.x;
+ ev.screen_drag.y=p_points[idx].pos.y;
+ ev.screen_drag.x=p_points[idx].pos.x - touch[i].pos.x;
+ ev.screen_drag.y=p_points[idx].pos.y - touch[i].pos.y;
+ main_loop->input_event(ev);
+ touch[i].pos=p_points[idx].pos;
+ }
+
+
+ } break;
+ case 2: { //release
+
+
+
+ if (touch.size()) {
+ //end all if exist
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_BUTTON;
+ ev.ID=++last_id;
+ ev.mouse_button.button_index=BUTTON_LEFT;
+ ev.mouse_button.button_mask=BUTTON_MASK_LEFT;
+ ev.mouse_button.pressed=false;
+ ev.mouse_button.x=touch[0].pos.x;
+ ev.mouse_button.y=touch[0].pos.y;
+ ev.mouse_button.global_x=touch[0].pos.x;
+ ev.mouse_button.global_y=touch[0].pos.y;
+ main_loop->input_event(ev);
+
+
+ for(int i=0;i<touch.size();i++) {
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_TOUCH;
+ ev.ID=++last_id;
+ ev.screen_touch.index=touch[i].id;
+ ev.screen_touch.pressed=false;
+ ev.screen_touch.x=touch[i].pos.x;
+ ev.screen_touch.y=touch[i].pos.y;
+ main_loop->input_event(ev);
+
+ }
+ }
+
+ } break;
+ case 3: { // add tuchi
+
+
+
+
+
+ ERR_FAIL_INDEX(p_pointer,p_points.size());
+
+ TouchPos tp=p_points[p_pointer];
+ touch.push_back(tp);
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_TOUCH;
+ ev.ID=++last_id;
+ ev.screen_touch.index=tp.id;
+ ev.screen_touch.pressed=true;
+ ev.screen_touch.x=tp.pos.x;
+ ev.screen_touch.y=tp.pos.y;
+ main_loop->input_event(ev);
+
+ } break;
+ case 4: {
+
+
+ for(int i=0;i<touch.size();i++) {
+ if (touch[i].id==p_pointer) {
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_TOUCH;
+ ev.ID=++last_id;
+ ev.screen_touch.index=touch[i].id;
+ ev.screen_touch.pressed=false;
+ ev.screen_touch.x=touch[i].pos.x;
+ ev.screen_touch.y=touch[i].pos.y;
+ main_loop->input_event(ev);
+ touch.remove(i);
+ i--;
+ }
+ }
+
+ } break;
+
+ }
+
+}
+
+OS_Android::OS_Android(int p_video_width,int p_video_height) {
+
+ default_videomode.width=p_video_width;
+ default_videomode.height=p_video_height;
+ default_videomode.fullscreen=true;
+ default_videomode.resizable=false;
+ main_loop=NULL;
+ last_id=1;
+}
+
+OS_Android::~OS_Android() {
+
+
+}
diff --git a/platform/android/.old/os_android.h b/platform/android/.old/os_android.h
new file mode 100644
index 0000000000..25ed84851a
--- /dev/null
+++ b/platform/android/.old/os_android.h
@@ -0,0 +1,108 @@
+#ifndef OS_ANDROID_H
+#define OS_ANDROID_H
+
+#include "os/input.h"
+#include "drivers/unix/os_unix.h"
+#include "os/main_loop.h"
+#include "servers/physics/physics_server_sw.h"
+#include "servers/spatial_sound/spatial_sound_server_sw.h"
+#include "servers/spatial_sound_2d/spatial_sound_2d_server_sw.h"
+#include "servers/audio/audio_server_sw.h"
+#include "servers/physics_2d/physics_2d_server_sw.h"
+#include "servers/visual/rasterizer.h"
+#include "audio_driver_android.h"
+
+class OS_Android : public OS_Unix {
+public:
+
+ struct TouchPos {
+ int id;
+ Point2 pos;
+ };
+private:
+
+ Vector<TouchPos> touch;
+
+ Point2 last_mouse;
+ unsigned int last_id;
+
+
+ Rasterizer *rasterizer;
+ VisualServer *visual_server;
+// AudioDriverPSP audio_driver_psp;
+ AudioServerSW *audio_server;
+ SampleManagerMallocSW *sample_manager;
+ SpatialSoundServerSW *spatial_sound_server;
+ SpatialSound2DServerSW *spatial_sound_2d_server;
+ PhysicsServer *physics_server;
+ Physics2DServer *physics_2d_server;
+ AudioDriverAndroid audio_driver_android;
+ InputDefault *input;
+
+ VideoMode default_videomode;
+ MainLoop * main_loop;
+public:
+
+
+ void initialize_core();
+
+ // functions used by main to initialize/deintialize the OS
+ virtual int get_video_driver_count() const;
+ virtual const char * get_video_driver_name(int p_driver) const;
+
+ virtual VideoMode get_default_video_mode() const;
+
+ virtual int get_audio_driver_count() const;
+ virtual const char * get_audio_driver_name(int p_driver) const;
+
+ virtual void initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver);
+
+ virtual void set_main_loop( MainLoop * p_main_loop );
+ virtual void delete_main_loop();
+
+ virtual void finalize();
+
+
+ typedef int64_t ProcessID;
+
+ static OS* get_singleton();
+
+ virtual void vprint(const char* p_format, va_list p_list, bool p_stderr=false);
+ virtual void print(const char *p_format, ... );
+ virtual void alert(const String& p_alert);
+
+
+ virtual void set_mouse_show(bool p_show);
+ virtual void set_mouse_grab(bool p_grab);
+ virtual bool is_mouse_grab_enabled() const;
+ virtual Point2 get_mouse_pos() const;
+ virtual int get_mouse_button_state() const;
+ virtual void set_window_title(const String& p_title);
+
+ //virtual void set_clipboard(const String& p_text);
+ //virtual String get_clipboard() const;
+
+ virtual void set_screen_orientation(ScreenOrientation p_orientation);
+
+ virtual void set_video_mode(const VideoMode& p_video_mode,int p_screen=0);
+ virtual VideoMode get_video_mode(int p_screen=0) const;
+ virtual void get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen=0) const;
+
+ virtual String get_name();
+ virtual MainLoop *get_main_loop() const;
+
+ virtual bool can_draw() const;
+
+ virtual void set_cursor_shape(CursorShape p_shape);
+
+ void main_loop_begin();
+ bool main_loop_iterate();
+ void main_loop_end();
+
+ void process_touch(int p_what,int p_pointer, const Vector<TouchPos>& p_points);
+ OS_Android(int p_video_width,int p_video_height);
+ ~OS_Android();
+
+};
+
+#endif
diff --git a/platform/android/.old/platform_config.h b/platform/android/.old/platform_config.h
new file mode 100644
index 0000000000..dad24432a5
--- /dev/null
+++ b/platform/android/.old/platform_config.h
@@ -0,0 +1 @@
+#include <alloca.h>
diff --git a/platform/android/.old/run_debug.sh b/platform/android/.old/run_debug.sh
new file mode 100755
index 0000000000..e39193bd55
--- /dev/null
+++ b/platform/android/.old/run_debug.sh
@@ -0,0 +1,40 @@
+
+# com.android.godot
+# for this, need to push gdbserver to device
+# adb push [location]/gdbserver /data/local
+
+# run
+
+DEBUG_PORT=5039
+GDB_PATH="$ANDROID_NDK_ROOT/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-gdb"
+
+#kill existing previous gdbserver if exists
+adb shell killall gdbserver
+run-as com.android.godot killall com.android.godot
+run-as com.android.godot killall gdbserver
+#get data dir of the app
+adb pull /system/bin/app_process app_process
+
+DATA_DIR=`adb shell run-as com.android.godot /system/bin/sh -c pwd | tr -d '\n\r'`
+echo "DATA DIR IS $DATA_DIR"
+#start app
+adb shell am start -n com.android.godot/com.android.godot.Godot
+#get the pid of the app
+PID=`adb shell pidof com.android.godot | tr -d '\n\r'`
+echo "PID IS: $PID hoho"
+#launch gdbserver
+DEBUG_SOCKET=debug-socket
+#echo adb shell /data/local/gdbserver +debug-socket --attach $PID
+adb shell run-as com.android.godot lib/gdbserver +$DEBUG_SOCKET --attach $PID &
+sleep 2s
+#adb shell /data/local/gdbserver localhost:$DEBUG_PORT --attach $PID &
+#setup network connection
+adb forward tcp:$DEBUG_PORT localfilesystem:$DATA_DIR/$DEBUG_SOCKET
+cp gdb.setup.base gdb.setup
+echo "target remote :$DEBUG_PORT" >> gdb.setup
+#echo "file
+$GDB_PATH -x gdb.setup
+
+
+
+
diff --git a/platform/android/AndroidManifest.xml.template b/platform/android/AndroidManifest.xml.template
new file mode 100644
index 0000000000..208d24059e
--- /dev/null
+++ b/platform/android/AndroidManifest.xml.template
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.godot.game"
+ android:versionCode="1"
+ android:versionName="1.0"
+ android:installLocation="preferExternal"
+ >
+ <application android:label="@string/godot_project_name_string" android:icon="@drawable/icon">
+ <activity android:name="com.android.godot.Godot"
+ android:label="@string/godot_project_name_string"
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+ android:launchMode="singleTask"
+ android:screenOrientation="landscape"
+ android:configChanges="orientation|keyboardHidden">
+
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+
+
+
+$$ADD_APPLICATION_CHUNKS$$
+
+ </application>
+ <uses-feature android:glEsVersion="0x00020000"/>
+ <uses-permission android:name="android.permission.INTERNET"></uses-permission>
+ <uses-permission android:name="android.permission.READ_CONTACTS"/>
+ <uses-permission android:name="com.android.vending.BILLING" />
+ <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+ <uses-permission android:name="android.permission.RECEIVE_SMS"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+
+
+ <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="11"/>
+
+</manifest>
diff --git a/platform/android/SCsub b/platform/android/SCsub
new file mode 100644
index 0000000000..327b1ffe09
--- /dev/null
+++ b/platform/android/SCsub
@@ -0,0 +1,66 @@
+import shutil
+
+Import('env')
+
+android_files = [
+
+ 'os_android.cpp',
+ 'godot_android.cpp',
+ 'file_access_android.cpp',
+ 'dir_access_android.cpp',
+ 'audio_driver_android.cpp',
+ 'file_access_jandroid.cpp',
+ 'dir_access_jandroid.cpp',
+ 'thread_jandroid.cpp',
+ 'audio_driver_jandroid.cpp',
+ 'android_native_app_glue.c',
+ 'java_glue.cpp'
+]
+
+#env.Depends('#core/math/vector3.h', 'vector3_psp.h')
+
+#obj = env.SharedObject('godot_android.cpp')
+
+env_android = env.Clone()
+if env['target'] == "profile":
+ env_android.Append(CPPFLAGS=['-DPROFILER_ENABLED'])
+
+android_objects=[]
+for x in android_files:
+ android_objects.append( env_android.SharedObject( x ) )
+
+prog = None
+
+abspath=env.Dir(".").abspath
+
+
+pp_basein = open(abspath+"/project.properties.template","rb")
+pp_baseout = open(abspath+"/java/project.properties","wb")
+pp_baseout.write( pp_basein.read() )
+refcount=1
+for x in env.android_source_modules:
+ pp_baseout.write("android.library.reference."+str(refcount)+"="+x+"\n")
+ refcount+=1
+
+
+
+pp_baseout.close()
+
+
+pp_basein = open(abspath+"/AndroidManifest.xml.template","rb")
+pp_baseout = open(abspath+"/java/AndroidManifest.xml","wb")
+manifest = pp_basein.read()
+manifest = manifest.replace("$$ADD_APPLICATION_CHUNKS$$",env.android_manifest_chunk)
+pp_baseout.write( manifest )
+
+
+for x in env.android_source_files:
+ shutil.copy(x,abspath+"/java/src/com/android/godot")
+
+for x in env.android_module_libraries:
+ shutil.copy(x,abspath+"/java/libs")
+
+
+env_android.SharedLibrary("#platform/android/libgodot_android.so",[android_objects])
+
+env.Command('#bin/libgodot_android.so', '#platform/android/libgodot_android.so', Copy('bin/libgodot_android.so', 'platform/android/libgodot_android.so'))
diff --git a/platform/android/android_native_app_glue.c b/platform/android/android_native_app_glue.c
new file mode 100644
index 0000000000..965f6284cd
--- /dev/null
+++ b/platform/android/android_native_app_glue.c
@@ -0,0 +1,437 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifdef ANDROID_NATIVE_ACTIVITY
+
+#include <jni.h>
+
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/resource.h>
+
+#include "android_native_app_glue.h"
+#include <android/log.h>
+
+#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "threaded_app", __VA_ARGS__))
+
+static void free_saved_state(struct android_app* android_app) {
+ pthread_mutex_lock(&android_app->mutex);
+ if (android_app->savedState != NULL) {
+ free(android_app->savedState);
+ android_app->savedState = NULL;
+ android_app->savedStateSize = 0;
+ }
+ pthread_mutex_unlock(&android_app->mutex);
+}
+
+int8_t android_app_read_cmd(struct android_app* android_app) {
+ int8_t cmd;
+ if (read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) {
+ switch (cmd) {
+ case APP_CMD_SAVE_STATE:
+ free_saved_state(android_app);
+ break;
+ }
+ return cmd;
+ } else {
+ LOGI("No data on command pipe!");
+ }
+ return -1;
+}
+
+static void print_cur_config(struct android_app* android_app) {
+ char lang[2], country[2];
+ AConfiguration_getLanguage(android_app->config, lang);
+ AConfiguration_getCountry(android_app->config, country);
+
+ LOGI("Config: mcc=%d mnc=%d lang=%c%c cnt=%c%c orien=%d touch=%d dens=%d "
+ "keys=%d nav=%d keysHid=%d navHid=%d sdk=%d size=%d long=%d "
+ "modetype=%d modenight=%d",
+ AConfiguration_getMcc(android_app->config),
+ AConfiguration_getMnc(android_app->config),
+ lang[0], lang[1], country[0], country[1],
+ AConfiguration_getOrientation(android_app->config),
+ AConfiguration_getTouchscreen(android_app->config),
+ AConfiguration_getDensity(android_app->config),
+ AConfiguration_getKeyboard(android_app->config),
+ AConfiguration_getNavigation(android_app->config),
+ AConfiguration_getKeysHidden(android_app->config),
+ AConfiguration_getNavHidden(android_app->config),
+ AConfiguration_getSdkVersion(android_app->config),
+ AConfiguration_getScreenSize(android_app->config),
+ AConfiguration_getScreenLong(android_app->config),
+ AConfiguration_getUiModeType(android_app->config),
+ AConfiguration_getUiModeNight(android_app->config));
+}
+
+void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd) {
+ switch (cmd) {
+ case APP_CMD_INPUT_CHANGED:
+ LOGI("APP_CMD_INPUT_CHANGED\n");
+ pthread_mutex_lock(&android_app->mutex);
+ if (android_app->inputQueue != NULL) {
+ AInputQueue_detachLooper(android_app->inputQueue);
+ }
+ android_app->inputQueue = android_app->pendingInputQueue;
+ if (android_app->inputQueue != NULL) {
+ LOGI("Attaching input queue to looper");
+ AInputQueue_attachLooper(android_app->inputQueue,
+ android_app->looper, LOOPER_ID_INPUT, NULL,
+ &android_app->inputPollSource);
+ }
+ pthread_cond_broadcast(&android_app->cond);
+ pthread_mutex_unlock(&android_app->mutex);
+ break;
+
+ case APP_CMD_INIT_WINDOW:
+ LOGI("APP_CMD_INIT_WINDOW\n");
+ pthread_mutex_lock(&android_app->mutex);
+ android_app->window = android_app->pendingWindow;
+ pthread_cond_broadcast(&android_app->cond);
+ pthread_mutex_unlock(&android_app->mutex);
+ break;
+
+ case APP_CMD_TERM_WINDOW:
+ LOGI("APP_CMD_TERM_WINDOW\n");
+ pthread_cond_broadcast(&android_app->cond);
+ break;
+
+ case APP_CMD_RESUME:
+ case APP_CMD_START:
+ case APP_CMD_PAUSE:
+ case APP_CMD_STOP:
+ LOGI("activityState=%d\n", cmd);
+ pthread_mutex_lock(&android_app->mutex);
+ android_app->activityState = cmd;
+ pthread_cond_broadcast(&android_app->cond);
+ pthread_mutex_unlock(&android_app->mutex);
+ break;
+
+ case APP_CMD_CONFIG_CHANGED:
+ LOGI("APP_CMD_CONFIG_CHANGED\n");
+ AConfiguration_fromAssetManager(android_app->config,
+ android_app->activity->assetManager);
+ print_cur_config(android_app);
+ break;
+
+ case APP_CMD_DESTROY:
+ LOGI("APP_CMD_DESTROY\n");
+ android_app->destroyRequested = 1;
+ break;
+ }
+}
+
+void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd) {
+ switch (cmd) {
+ case APP_CMD_TERM_WINDOW:
+ LOGI("APP_CMD_TERM_WINDOW\n");
+ pthread_mutex_lock(&android_app->mutex);
+ android_app->window = NULL;
+ pthread_cond_broadcast(&android_app->cond);
+ pthread_mutex_unlock(&android_app->mutex);
+ break;
+
+ case APP_CMD_SAVE_STATE:
+ LOGI("APP_CMD_SAVE_STATE\n");
+ pthread_mutex_lock(&android_app->mutex);
+ android_app->stateSaved = 1;
+ pthread_cond_broadcast(&android_app->cond);
+ pthread_mutex_unlock(&android_app->mutex);
+ break;
+
+ case APP_CMD_RESUME:
+ free_saved_state(android_app);
+ break;
+ }
+}
+
+void app_dummy() {
+
+}
+
+static void android_app_destroy(struct android_app* android_app) {
+ LOGI("android_app_destroy!");
+ free_saved_state(android_app);
+ pthread_mutex_lock(&android_app->mutex);
+ if (android_app->inputQueue != NULL) {
+ AInputQueue_detachLooper(android_app->inputQueue);
+ }
+ AConfiguration_delete(android_app->config);
+ android_app->destroyed = 1;
+ pthread_cond_broadcast(&android_app->cond);
+ pthread_mutex_unlock(&android_app->mutex);
+ // Can't touch android_app object after this.
+}
+
+static void process_input(struct android_app* app, struct android_poll_source* source) {
+ AInputEvent* event = NULL;
+ if (AInputQueue_getEvent(app->inputQueue, &event) >= 0) {
+ LOGI("New input event: type=%d\n", AInputEvent_getType(event));
+ if (AInputQueue_preDispatchEvent(app->inputQueue, event)) {
+ return;
+ }
+ int32_t handled = 0;
+ if (app->onInputEvent != NULL) handled = app->onInputEvent(app, event);
+ AInputQueue_finishEvent(app->inputQueue, event, handled);
+ } else {
+ LOGI("Failure reading next input event: %s\n", strerror(errno));
+ }
+}
+
+static void process_cmd(struct android_app* app, struct android_poll_source* source) {
+ int8_t cmd = android_app_read_cmd(app);
+ android_app_pre_exec_cmd(app, cmd);
+ if (app->onAppCmd != NULL) app->onAppCmd(app, cmd);
+ android_app_post_exec_cmd(app, cmd);
+}
+
+static void* android_app_entry(void* param) {
+ struct android_app* android_app = (struct android_app*)param;
+
+ android_app->config = AConfiguration_new();
+ AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager);
+
+ print_cur_config(android_app);
+
+ android_app->cmdPollSource.id = LOOPER_ID_MAIN;
+ android_app->cmdPollSource.app = android_app;
+ android_app->cmdPollSource.process = process_cmd;
+ android_app->inputPollSource.id = LOOPER_ID_INPUT;
+ android_app->inputPollSource.app = android_app;
+ android_app->inputPollSource.process = process_input;
+
+ ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
+ ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL,
+ &android_app->cmdPollSource);
+ android_app->looper = looper;
+
+ pthread_mutex_lock(&android_app->mutex);
+ android_app->running = 1;
+ pthread_cond_broadcast(&android_app->cond);
+ pthread_mutex_unlock(&android_app->mutex);
+
+ android_main(android_app);
+
+ android_app_destroy(android_app);
+ return NULL;
+}
+
+// --------------------------------------------------------------------
+// Native activity interaction (called from main thread)
+// --------------------------------------------------------------------
+
+static struct android_app* android_app_create(ANativeActivity* activity,
+ void* savedState, size_t savedStateSize) {
+ struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app));
+ memset(android_app, 0, sizeof(struct android_app));
+ android_app->activity = activity;
+
+ pthread_mutex_init(&android_app->mutex, NULL);
+ pthread_cond_init(&android_app->cond, NULL);
+
+ if (savedState != NULL) {
+ android_app->savedState = malloc(savedStateSize);
+ android_app->savedStateSize = savedStateSize;
+ memcpy(android_app->savedState, savedState, savedStateSize);
+ }
+
+ int msgpipe[2];
+ if (pipe(msgpipe)) {
+ LOGI("could not create pipe: %s", strerror(errno));
+ }
+ android_app->msgread = msgpipe[0];
+ android_app->msgwrite = msgpipe[1];
+
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ pthread_create(&android_app->thread, &attr, android_app_entry, android_app);
+
+ // Wait for thread to start.
+ pthread_mutex_lock(&android_app->mutex);
+ while (!android_app->running) {
+ pthread_cond_wait(&android_app->cond, &android_app->mutex);
+ }
+ pthread_mutex_unlock(&android_app->mutex);
+
+ return android_app;
+}
+
+static void android_app_write_cmd(struct android_app* android_app, int8_t cmd) {
+ if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) {
+ LOGI("Failure writing android_app cmd: %s\n", strerror(errno));
+ }
+}
+
+static void android_app_set_input(struct android_app* android_app, AInputQueue* inputQueue) {
+ pthread_mutex_lock(&android_app->mutex);
+ android_app->pendingInputQueue = inputQueue;
+ android_app_write_cmd(android_app, APP_CMD_INPUT_CHANGED);
+ while (android_app->inputQueue != android_app->pendingInputQueue) {
+ pthread_cond_wait(&android_app->cond, &android_app->mutex);
+ }
+ pthread_mutex_unlock(&android_app->mutex);
+}
+
+static void android_app_set_window(struct android_app* android_app, ANativeWindow* window) {
+ pthread_mutex_lock(&android_app->mutex);
+ if (android_app->pendingWindow != NULL) {
+ android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW);
+ }
+ android_app->pendingWindow = window;
+ if (window != NULL) {
+ android_app_write_cmd(android_app, APP_CMD_INIT_WINDOW);
+ }
+ while (android_app->window != android_app->pendingWindow) {
+ pthread_cond_wait(&android_app->cond, &android_app->mutex);
+ }
+ pthread_mutex_unlock(&android_app->mutex);
+}
+
+static void android_app_set_activity_state(struct android_app* android_app, int8_t cmd) {
+ pthread_mutex_lock(&android_app->mutex);
+ android_app_write_cmd(android_app, cmd);
+ while (android_app->activityState != cmd) {
+ pthread_cond_wait(&android_app->cond, &android_app->mutex);
+ }
+ pthread_mutex_unlock(&android_app->mutex);
+}
+
+static void android_app_free(struct android_app* android_app) {
+ pthread_mutex_lock(&android_app->mutex);
+ android_app_write_cmd(android_app, APP_CMD_DESTROY);
+ while (!android_app->destroyed) {
+ pthread_cond_wait(&android_app->cond, &android_app->mutex);
+ }
+ pthread_mutex_unlock(&android_app->mutex);
+
+ close(android_app->msgread);
+ close(android_app->msgwrite);
+ pthread_cond_destroy(&android_app->cond);
+ pthread_mutex_destroy(&android_app->mutex);
+ free(android_app);
+}
+
+static void onDestroy(ANativeActivity* activity) {
+ LOGI("Destroy: %p\n", activity);
+ android_app_free((struct android_app*)activity->instance);
+}
+
+static void onStart(ANativeActivity* activity) {
+ LOGI("Start: %p\n", activity);
+ android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_START);
+}
+
+static void onResume(ANativeActivity* activity) {
+ LOGI("Resume: %p\n", activity);
+ android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_RESUME);
+}
+
+static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) {
+ struct android_app* android_app = (struct android_app*)activity->instance;
+ void* savedState = NULL;
+
+ LOGI("SaveInstanceState: %p\n", activity);
+ pthread_mutex_lock(&android_app->mutex);
+ android_app->stateSaved = 0;
+ android_app_write_cmd(android_app, APP_CMD_SAVE_STATE);
+ while (!android_app->stateSaved) {
+ pthread_cond_wait(&android_app->cond, &android_app->mutex);
+ }
+
+ if (android_app->savedState != NULL) {
+ savedState = android_app->savedState;
+ *outLen = android_app->savedStateSize;
+ android_app->savedState = NULL;
+ android_app->savedStateSize = 0;
+ }
+
+ pthread_mutex_unlock(&android_app->mutex);
+
+ return savedState;
+}
+
+static void onPause(ANativeActivity* activity) {
+ LOGI("Pause: %p\n", activity);
+ android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_PAUSE);
+}
+
+static void onStop(ANativeActivity* activity) {
+ LOGI("Stop: %p\n", activity);
+ android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_STOP);
+}
+
+static void onConfigurationChanged(ANativeActivity* activity) {
+ struct android_app* android_app = (struct android_app*)activity->instance;
+ LOGI("ConfigurationChanged: %p\n", activity);
+ android_app_write_cmd(android_app, APP_CMD_CONFIG_CHANGED);
+}
+
+static void onLowMemory(ANativeActivity* activity) {
+ struct android_app* android_app = (struct android_app*)activity->instance;
+ LOGI("LowMemory: %p\n", activity);
+ android_app_write_cmd(android_app, APP_CMD_LOW_MEMORY);
+}
+
+static void onWindowFocusChanged(ANativeActivity* activity, int focused) {
+ LOGI("WindowFocusChanged: %p -- %d\n", activity, focused);
+ android_app_write_cmd((struct android_app*)activity->instance,
+ focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS);
+}
+
+static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window) {
+ LOGI("NativeWindowCreated: %p -- %p\n", activity, window);
+ android_app_set_window((struct android_app*)activity->instance, window);
+}
+
+static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) {
+ LOGI("NativeWindowDestroyed: %p -- %p\n", activity, window);
+ android_app_set_window((struct android_app*)activity->instance, NULL);
+}
+
+static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue) {
+ LOGI("InputQueueCreated: %p -- %p\n", activity, queue);
+ android_app_set_input((struct android_app*)activity->instance, queue);
+}
+
+static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue) {
+ LOGI("InputQueueDestroyed: %p -- %p\n", activity, queue);
+ android_app_set_input((struct android_app*)activity->instance, NULL);
+}
+
+void ANativeActivity_onCreate(ANativeActivity* activity,
+ void* savedState, size_t savedStateSize) {
+ LOGI("Creating: %p\n", activity);
+ activity->callbacks->onDestroy = onDestroy;
+ activity->callbacks->onStart = onStart;
+ activity->callbacks->onResume = onResume;
+ activity->callbacks->onSaveInstanceState = onSaveInstanceState;
+ activity->callbacks->onPause = onPause;
+ activity->callbacks->onStop = onStop;
+ activity->callbacks->onConfigurationChanged = onConfigurationChanged;
+ activity->callbacks->onLowMemory = onLowMemory;
+ activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
+ activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
+ activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
+ activity->callbacks->onInputQueueCreated = onInputQueueCreated;
+ activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
+
+ activity->instance = android_app_create(activity, savedState, savedStateSize);
+}
+#endif
diff --git a/platform/android/android_native_app_glue.h b/platform/android/android_native_app_glue.h
new file mode 100644
index 0000000000..fe8684b5d2
--- /dev/null
+++ b/platform/android/android_native_app_glue.h
@@ -0,0 +1,378 @@
+/*************************************************************************/
+/* android_native_app_glue.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef _ANDROID_NATIVE_APP_GLUE_H
+#define _ANDROID_NATIVE_APP_GLUE_H
+#ifdef ANDROID_NATIVE_ACTIVITY
+
+#include <poll.h>
+#include <pthread.h>
+#include <sched.h>
+
+#include <android/configuration.h>
+#include <android/looper.h>
+#include <android/native_activity.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The native activity interface provided by <android/native_activity.h>
+ * is based on a set of application-provided callbacks that will be called
+ * by the Activity's main thread when certain events occur.
+ *
+ * This means that each one of this callbacks _should_ _not_ block, or they
+ * risk having the system force-close the application. This programming
+ * model is direct, lightweight, but constraining.
+ *
+ * The 'threaded_native_app' static library is used to provide a different
+ * execution model where the application can implement its own main event
+ * loop in a different thread instead. Here's how it works:
+ *
+ * 1/ The application must provide a function named "android_main()" that
+ * will be called when the activity is created, in a new thread that is
+ * distinct from the activity's main thread.
+ *
+ * 2/ android_main() receives a pointer to a valid "android_app" structure
+ * that contains references to other important objects, e.g. the
+ * ANativeActivity obejct instance the application is running in.
+ *
+ * 3/ the "android_app" object holds an ALooper instance that already
+ * listens to two important things:
+ *
+ * - activity lifecycle events (e.g. "pause", "resume"). See APP_CMD_XXX
+ * declarations below.
+ *
+ * - input events coming from the AInputQueue attached to the activity.
+ *
+ * Each of these correspond to an ALooper identifier returned by
+ * ALooper_pollOnce with values of LOOPER_ID_MAIN and LOOPER_ID_INPUT,
+ * respectively.
+ *
+ * Your application can use the same ALooper to listen to additional
+ * file-descriptors. They can either be callback based, or with return
+ * identifiers starting with LOOPER_ID_USER.
+ *
+ * 4/ Whenever you receive a LOOPER_ID_MAIN or LOOPER_ID_INPUT event,
+ * the returned data will point to an android_poll_source structure. You
+ * can call the process() function on it, and fill in android_app->onAppCmd
+ * and android_app->onInputEvent to be called for your own processing
+ * of the event.
+ *
+ * Alternatively, you can call the low-level functions to read and process
+ * the data directly... look at the process_cmd() and process_input()
+ * implementations in the glue to see how to do this.
+ *
+ * See the sample named "native-activity" that comes with the NDK with a
+ * full usage example. Also look at the JavaDoc of NativeActivity.
+ */
+
+struct android_app;
+
+/**
+ * Data associated with an ALooper fd that will be returned as the "outData"
+ * when that source has data ready.
+ */
+struct android_poll_source {
+ // The identifier of this source. May be LOOPER_ID_MAIN or
+ // LOOPER_ID_INPUT.
+ int32_t id;
+
+ // The android_app this ident is associated with.
+ struct android_app* app;
+
+ // Function to call to perform the standard processing of data from
+ // this source.
+ void (*process)(struct android_app* app, struct android_poll_source* source);
+};
+
+/**
+ * This is the interface for the standard glue code of a threaded
+ * application. In this model, the application's code is running
+ * in its own thread separate from the main thread of the process.
+ * It is not required that this thread be associated with the Java
+ * VM, although it will need to be in order to make JNI calls any
+ * Java objects.
+ */
+struct android_app {
+ // The application can place a pointer to its own state object
+ // here if it likes.
+ void* userData;
+
+ // Fill this in with the function to process main app commands (APP_CMD_*)
+ void (*onAppCmd)(struct android_app* app, int32_t cmd);
+
+ // Fill this in with the function to process input events. At this point
+ // the event has already been pre-dispatched, and it will be finished upon
+ // return. Return 1 if you have handled the event, 0 for any default
+ // dispatching.
+ int32_t (*onInputEvent)(struct android_app* app, AInputEvent* event);
+
+ // The ANativeActivity object instance that this app is running in.
+ ANativeActivity* activity;
+
+ // The current configuration the app is running in.
+ AConfiguration* config;
+
+ // This is the last instance's saved state, as provided at creation time.
+ // It is NULL if there was no state. You can use this as you need; the
+ // memory will remain around until you call android_app_exec_cmd() for
+ // APP_CMD_RESUME, at which point it will be freed and savedState set to NULL.
+ // These variables should only be changed when processing a APP_CMD_SAVE_STATE,
+ // at which point they will be initialized to NULL and you can malloc your
+ // state and place the information here. In that case the memory will be
+ // freed for you later.
+ void* savedState;
+ size_t savedStateSize;
+
+ // The ALooper associated with the app's thread.
+ ALooper* looper;
+
+ // When non-NULL, this is the input queue from which the app will
+ // receive user input events.
+ AInputQueue* inputQueue;
+
+ // When non-NULL, this is the window surface that the app can draw in.
+ ANativeWindow* window;
+
+ // Current content rectangle of the window; this is the area where the
+ // window's content should be placed to be seen by the user.
+ ARect contentRect;
+
+ // Current state of the app's activity. May be either APP_CMD_START,
+ // APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below.
+ int activityState;
+
+ // This is non-zero when the application's NativeActivity is being
+ // destroyed and waiting for the app thread to complete.
+ int destroyRequested;
+
+ // -------------------------------------------------
+ // Below are "private" implementation of the glue code.
+
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+
+ int msgread;
+ int msgwrite;
+
+ pthread_t thread;
+
+ struct android_poll_source cmdPollSource;
+ struct android_poll_source inputPollSource;
+
+ int running;
+ int stateSaved;
+ int destroyed;
+ int redrawNeeded;
+ AInputQueue* pendingInputQueue;
+ ANativeWindow* pendingWindow;
+ ARect pendingContentRect;
+};
+
+enum {
+ /**
+ * Looper data ID of commands coming from the app's main thread, which
+ * is returned as an identifier from ALooper_pollOnce(). The data for this
+ * identifier is a pointer to an android_poll_source structure.
+ * These can be retrieved and processed with android_app_read_cmd()
+ * and android_app_exec_cmd().
+ */
+ LOOPER_ID_MAIN = 1,
+
+ /**
+ * Looper data ID of events coming from the AInputQueue of the
+ * application's window, which is returned as an identifier from
+ * ALooper_pollOnce(). The data for this identifier is a pointer to an
+ * android_poll_source structure. These can be read via the inputQueue
+ * object of android_app.
+ */
+ LOOPER_ID_INPUT = 2,
+
+ /**
+ * Start of user-defined ALooper identifiers.
+ */
+ LOOPER_ID_USER = 3,
+};
+
+enum {
+ /**
+ * Command from main thread: the AInputQueue has changed. Upon processing
+ * this command, android_app->inputQueue will be updated to the new queue
+ * (or NULL).
+ */
+ APP_CMD_INPUT_CHANGED,
+
+ /**
+ * Command from main thread: a new ANativeWindow is ready for use. Upon
+ * receiving this command, android_app->window will contain the new window
+ * surface.
+ */
+ APP_CMD_INIT_WINDOW,
+
+ /**
+ * Command from main thread: the existing ANativeWindow needs to be
+ * terminated. Upon receiving this command, android_app->window still
+ * contains the existing window; after calling android_app_exec_cmd
+ * it will be set to NULL.
+ */
+ APP_CMD_TERM_WINDOW,
+
+ /**
+ * Command from main thread: the current ANativeWindow has been resized.
+ * Please redraw with its new size.
+ */
+ APP_CMD_WINDOW_RESIZED,
+
+ /**
+ * Command from main thread: the system needs that the current ANativeWindow
+ * be redrawn. You should redraw the window before handing this to
+ * android_app_exec_cmd() in order to avoid transient drawing glitches.
+ */
+ APP_CMD_WINDOW_REDRAW_NEEDED,
+
+ /**
+ * Command from main thread: the content area of the window has changed,
+ * such as from the soft input window being shown or hidden. You can
+ * find the new content rect in android_app::contentRect.
+ */
+ APP_CMD_CONTENT_RECT_CHANGED,
+
+ /**
+ * Command from main thread: the app's activity window has gained
+ * input focus.
+ */
+ APP_CMD_GAINED_FOCUS,
+
+ /**
+ * Command from main thread: the app's activity window has lost
+ * input focus.
+ */
+ APP_CMD_LOST_FOCUS,
+
+ /**
+ * Command from main thread: the current device configuration has changed.
+ */
+ APP_CMD_CONFIG_CHANGED,
+
+ /**
+ * Command from main thread: the system is running low on memory.
+ * Try to reduce your memory use.
+ */
+ APP_CMD_LOW_MEMORY,
+
+ /**
+ * Command from main thread: the app's activity has been started.
+ */
+ APP_CMD_START,
+
+ /**
+ * Command from main thread: the app's activity has been resumed.
+ */
+ APP_CMD_RESUME,
+
+ /**
+ * Command from main thread: the app should generate a new saved state
+ * for itself, to restore from later if needed. If you have saved state,
+ * allocate it with malloc and place it in android_app.savedState with
+ * the size in android_app.savedStateSize. The will be freed for you
+ * later.
+ */
+ APP_CMD_SAVE_STATE,
+
+ /**
+ * Command from main thread: the app's activity has been paused.
+ */
+ APP_CMD_PAUSE,
+
+ /**
+ * Command from main thread: the app's activity has been stopped.
+ */
+ APP_CMD_STOP,
+
+ /**
+ * Command from main thread: the app's activity is being destroyed,
+ * and waiting for the app thread to clean up and exit before proceeding.
+ */
+ APP_CMD_DESTROY,
+};
+
+/**
+ * Call when ALooper_pollAll() returns LOOPER_ID_MAIN, reading the next
+ * app command message.
+ */
+int8_t android_app_read_cmd(struct android_app* android_app);
+
+/**
+ * Call with the command returned by android_app_read_cmd() to do the
+ * initial pre-processing of the given command. You can perform your own
+ * actions for the command after calling this function.
+ */
+void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd);
+
+/**
+ * Call with the command returned by android_app_read_cmd() to do the
+ * final post-processing of the given command. You must have done your own
+ * actions for the command before calling this function.
+ */
+void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd);
+
+/**
+ * Dummy function you can call to ensure glue code isn't stripped.
+ */
+void app_dummy();
+
+/**
+ * This is the function that application code must implement, representing
+ * the main entry to the app.
+ */
+extern void android_main(struct android_app* app);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ANDROID_NATIVE_APP_GLUE_H */
+#endif
diff --git a/platform/android/audio_driver_android.cpp b/platform/android/audio_driver_android.cpp
new file mode 100644
index 0000000000..4f7b4ee348
--- /dev/null
+++ b/platform/android/audio_driver_android.cpp
@@ -0,0 +1,393 @@
+/*************************************************************************/
+/* audio_driver_android.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "audio_driver_android.h"
+#include <string.h>
+#ifdef ANDROID_NATIVE_ACTIVITY
+
+
+
+
+
+#define MAX_NUMBER_INTERFACES 3
+#define MAX_NUMBER_OUTPUT_DEVICES 6
+
+/* Structure for passing information to callback function */
+
+
+void AudioDriverAndroid::_buffer_callback(
+ SLAndroidSimpleBufferQueueItf queueItf
+ /* SLuint32 eventFlags,
+ const void * pBuffer,
+ SLuint32 bufferSize,
+ SLuint32 dataUsed*/) {
+
+
+
+ if (mutex)
+ mutex->lock();
+
+ audio_server_process(buffer_size,mixdown_buffer);
+
+ if (mutex)
+ mutex->unlock();
+
+
+ const int32_t* src_buff=mixdown_buffer;
+
+ int16_t *ptr = (int16_t*)buffers[last_free];
+ last_free=(last_free+1)%BUFFER_COUNT;
+
+ for(int i=0;i<buffer_size*2;i++) {
+
+ ptr[i]=src_buff[i]>>16;
+ }
+
+ (*queueItf)->Enqueue(queueItf, ptr, 4 * buffer_size);
+
+
+#if 0
+ SLresult res;
+ CallbackCntxt *pCntxt = (CallbackCntxt*)pContext;
+ if(pCntxt->pData < (pCntxt->pDataBase + pCntxt->size))
+ {
+ res = (*queueItf)->Enqueue(queueItf, (void*) pCntxt->pData,
+ 2 * AUDIO_DATA_BUFFER_SIZE, SL_BOOLEAN_FALSE); /* Size given
+ in bytes. */
+ CheckErr(res);
+ /* Increase data pointer by buffer size */
+ pCntxt->pData += AUDIO_DATA_BUFFER_SIZE;
+ }
+ }
+#endif
+}
+
+void AudioDriverAndroid::_buffer_callbacks(
+ SLAndroidSimpleBufferQueueItf queueItf,
+ /*SLuint32 eventFlags,
+ const void * pBuffer,
+ SLuint32 bufferSize,
+ SLuint32 dataUsed,*/
+ void *pContext) {
+
+
+ AudioDriverAndroid *ad = (AudioDriverAndroid*)pContext;
+
+// ad->_buffer_callback(queueItf,eventFlags,pBuffer,bufferSize,dataUsed);
+ ad->_buffer_callback(queueItf);
+
+}
+
+
+AudioDriverAndroid* AudioDriverAndroid::s_ad=NULL;
+
+const char* AudioDriverAndroid::get_name() const {
+
+ return "Android";
+}
+
+#if 0
+int AudioDriverAndroid::thread_func(SceSize args, void *argp) {
+
+ AudioDriverAndroid* ad = s_ad;
+ sceAudioOutput2Reserve(AUDIO_OUTPUT_SAMPLE);
+
+ int half=0;
+ while(!ad->exit_thread) {
+
+ int16_t *ptr = &ad->outbuff[AUDIO_OUTPUT_SAMPLE*2*half];
+
+
+
+ if (!ad->active) {
+
+ for(int i=0;i<AUDIO_OUTPUT_SAMPLE*2;i++) {
+ ptr[i]=0;
+ }
+
+ } else {
+
+ //printf("samples: %i\n",AUDIO_OUTPUT_SAMPLE);
+ ad->lock();
+
+ ad->audio_server_process(AUDIO_OUTPUT_SAMPLE,ad->outbuff_32);
+
+ ad->unlock();
+
+ const int32_t* src_buff=ad->outbuff_32;
+
+ for(int i=0;i<AUDIO_OUTPUT_SAMPLE*2;i++) {
+
+ ptr[i]=src_buff[i]>>16;
+ }
+ }
+
+
+ /* Output 16-bit PCM STEREO data that is in pcmBuf without changing the volume */
+ sceAudioOutput2OutputBlocking(
+ SCE_AUDIO_VOLUME_0dB*3, //0db at 0x8000, that's obvious
+ ptr
+ );
+
+ if (half)
+ half=0;
+ else
+ half=1;
+
+ }
+
+ sceAudioOutput2Release();
+
+ sceKernelExitThread(SCE_KERNEL_EXIT_SUCCESS);
+ ad->thread_exited=true;
+ return SCE_KERNEL_EXIT_SUCCESS;
+
+}
+
+#endif
+Error AudioDriverAndroid::init(){
+
+ SLresult
+ res;
+ SLEngineOption EngineOption[] = {
+ (SLuint32) SL_ENGINEOPTION_THREADSAFE,
+ (SLuint32) SL_BOOLEAN_TRUE
+
+ };
+ res = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL);
+ if (res!=SL_RESULT_SUCCESS) {
+
+ ERR_EXPLAIN("Could not Initialize OpenSL");
+ ERR_FAIL_V(ERR_INVALID_PARAMETER);
+ }
+ res = (*sl)->Realize(sl, SL_BOOLEAN_FALSE);
+ if (res!=SL_RESULT_SUCCESS) {
+
+ ERR_EXPLAIN("Could not Realize OpenSL");
+ ERR_FAIL_V(ERR_INVALID_PARAMETER);
+ }
+
+ print_line("OpenSL Init OK!");
+
+ return OK;
+
+}
+void AudioDriverAndroid::start(){
+
+
+ mutex = Mutex::create();
+ active=false;
+
+
+ SLint32 numOutputs = 0;
+ SLuint32 deviceID = 0;
+ SLresult res;
+
+
+ buffer_size = 1024;
+
+ for(int i=0;i<BUFFER_COUNT;i++) {
+
+ buffers[i]=memnew_arr( int16_t,buffer_size*2 );
+ memset(buffers[i],0,buffer_size*4);
+ }
+
+ mixdown_buffer = memnew_arr( int32_t,buffer_size* 2);
+
+ /* Callback context for the buffer queue callback function */
+
+ /* Get the SL Engine Interface which is implicit */
+ res = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf);
+
+ ERR_FAIL_COND( res !=SL_RESULT_SUCCESS );
+ /* Initialize arrays required[] and iidArray[] */
+ int i;
+ SLboolean required[MAX_NUMBER_INTERFACES];
+ SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
+
+#if 0
+
+ for (i=0; i<MAX_NUMBER_INTERFACES; i++)
+ {
+ required[i] = SL_BOOLEAN_FALSE;
+ iidArray[i] = SL_IID_NULL;
+ }
+ // Set arrays required[] and iidArray[] for VOLUME interface
+ required[0] = SL_BOOLEAN_TRUE;
+ iidArray[0] = SL_IID_VOLUME;
+
+ // Create Output Mix object to be used by player
+ res = (*EngineItf)->CreateOutputMix(EngineItf, &OutputMix, 1,
+ iidArray, required);
+#else
+
+ {
+ const SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB};
+ const SLboolean req[1] = {SL_BOOLEAN_FALSE};
+ res = (*EngineItf)->CreateOutputMix(EngineItf, &OutputMix, 0,
+ ids, req);
+ }
+
+
+#endif
+ ERR_FAIL_COND( res !=SL_RESULT_SUCCESS );
+ // Realizing the Output Mix object in synchronous mode.
+ res = (*OutputMix)->Realize(OutputMix, SL_BOOLEAN_FALSE);
+ ERR_FAIL_COND( res !=SL_RESULT_SUCCESS );
+
+ SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, BUFFER_COUNT};
+// bufferQueue.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
+// bufferQueue.numBuffers = BUFFER_COUNT; /* Four buffers in our buffer queue */
+ /* Setup the format of the content in the buffer queue */
+ pcm.formatType = SL_DATAFORMAT_PCM;
+ pcm.numChannels = 2;
+ pcm.samplesPerSec = SL_SAMPLINGRATE_44_1;
+ pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
+ pcm.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16;
+ pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
+#ifdef BIG_ENDIAN_ENABLED
+ pcm.endianness = SL_BYTEORDER_BIGENDIAN;
+#else
+ pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
+#endif
+ audioSource.pFormat = (void *)&pcm;
+ audioSource.pLocator = (void *)&loc_bufq;
+
+
+ /* Setup the data sink structure */
+ locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
+ locator_outputmix.outputMix= OutputMix;
+ audioSink.pLocator = (void *)&locator_outputmix;
+ audioSink.pFormat = NULL;
+ /* Initialize the context for Buffer queue callbacks */
+// cntxt.pDataBase = (void*)&pcmData;
+ //cntxt.pData = cntxt.pDataBase;
+ //cntxt.size = sizeof(pcmData);
+ /* Set arrays required[] and iidArray[] for SEEK interface
+ (PlayItf is implicit) */
+ required[0] = SL_BOOLEAN_TRUE;
+ iidArray[0] = SL_IID_BUFFERQUEUE;
+ /* Create the music player */
+
+ {
+ const SLInterfaceID ids[2] = {SL_IID_BUFFERQUEUE, SL_IID_EFFECTSEND};
+ const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
+
+ res = (*EngineItf)->CreateAudioPlayer(EngineItf, &player,
+ &audioSource, &audioSink, 1, ids, req);
+ ERR_FAIL_COND( res !=SL_RESULT_SUCCESS );
+ }
+ /* Realizing the player in synchronous mode. */
+ res = (*player)->Realize(player, SL_BOOLEAN_FALSE);
+ ERR_FAIL_COND( res !=SL_RESULT_SUCCESS );
+ /* Get seek and play interfaces */
+ res = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf);
+ ERR_FAIL_COND( res !=SL_RESULT_SUCCESS );
+ res = (*player)->GetInterface(player, SL_IID_BUFFERQUEUE,
+ (void*)&bufferQueueItf);
+ ERR_FAIL_COND( res !=SL_RESULT_SUCCESS );
+ /* Setup to receive buffer queue event callbacks */
+ res = (*bufferQueueItf)->RegisterCallback(bufferQueueItf,
+ _buffer_callbacks, this);
+ ERR_FAIL_COND( res !=SL_RESULT_SUCCESS );
+ /* Before we start set volume to -3dB (-300mB) */
+#if 0
+ res = (*OutputMix)->GetInterface(OutputMix, SL_IID_VOLUME,
+ (void*)&volumeItf);
+ ERR_FAIL_COND( res !=SL_RESULT_SUCCESS );
+ /* Setup the data source structure for the buffer queue */
+
+ res = (*volumeItf)->SetVolumeLevel(volumeItf, -300);
+ ERR_FAIL_COND( res !=SL_RESULT_SUCCESS );
+#endif
+ last_free=0;
+#if 1
+ //fill up buffers
+ for(int i=0;i<BUFFER_COUNT;i++) {
+ /* Enqueue a few buffers to get the ball rolling */
+ res = (*bufferQueueItf)->Enqueue(bufferQueueItf, buffers[i],
+ 4 * buffer_size); /* Size given in */
+
+ }
+#endif
+
+ res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING);
+ ERR_FAIL_COND( res !=SL_RESULT_SUCCESS );
+
+#if 0
+ res = (*bufferQueueItf)->GetState(bufferQueueItf, &state);
+ ERR_FAIL_COND( res !=SL_RESULT_SUCCESS );
+ while(state.count)
+ {
+ (*bufferQueueItf)->GetState(bufferQueueItf, &state);
+ }
+ /* Make sure player is stopped */
+ res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
+ CheckErr(res);
+ /* Destroy the player */
+ (*player)->Destroy(player);
+ /* Destroy Output Mix object */
+ (*OutputMix)->Destroy(OutputMix);
+#endif
+
+ active=true;
+}
+int AudioDriverAndroid::get_mix_rate() const {
+
+ return 44100;
+}
+AudioDriverSW::OutputFormat AudioDriverAndroid::get_output_format() const{
+
+ return OUTPUT_STEREO;
+}
+void AudioDriverAndroid::lock(){
+
+ //if (active && mutex)
+ // mutex->lock();
+
+}
+void AudioDriverAndroid::unlock() {
+
+ //if (active && mutex)
+ // mutex->unlock();
+
+}
+void AudioDriverAndroid::finish(){
+
+ (*sl)->Destroy(sl);
+
+}
+
+
+AudioDriverAndroid::AudioDriverAndroid()
+{
+ s_ad=this;
+ mutex=NULL;
+}
+
+#endif
diff --git a/platform/android/audio_driver_android.h b/platform/android/audio_driver_android.h
new file mode 100644
index 0000000000..655772c772
--- /dev/null
+++ b/platform/android/audio_driver_android.h
@@ -0,0 +1,105 @@
+/*************************************************************************/
+/* audio_driver_android.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef AUDIO_DRIVER_ANDROID_H
+#define AUDIO_DRIVER_ANDROID_H
+
+#ifdef ANDROID_NATIVE_ACTIVITY
+
+#include "servers/audio/audio_server_sw.h"
+#include "os/mutex.h"
+#include <SLES/OpenSLES.h>
+#include "SLES/OpenSLES_Android.h"
+class AudioDriverAndroid : public AudioDriverSW {
+
+ bool active;
+ Mutex *mutex;
+
+ enum {
+
+ BUFFER_COUNT=2
+ };
+
+
+
+
+ uint32_t buffer_size;
+ int16_t *buffers[BUFFER_COUNT];
+ int32_t *mixdown_buffer;
+ int last_free;
+
+
+ SLPlayItf playItf;
+ SLObjectItf sl;
+ SLEngineItf EngineItf;
+ SLObjectItf OutputMix;
+ SLVolumeItf volumeItf;
+ SLObjectItf player;
+ SLAndroidSimpleBufferQueueItf bufferQueueItf;
+ SLDataSource audioSource;
+ SLDataFormat_PCM pcm;
+ SLDataSink audioSink;
+ SLDataLocator_OutputMix locator_outputmix;
+ SLBufferQueueState state;
+
+ static AudioDriverAndroid* s_ad;
+
+ void _buffer_callback(
+ SLAndroidSimpleBufferQueueItf queueItf
+ /* SLuint32 eventFlags,
+ const void * pBuffer,
+ SLuint32 bufferSize,
+ SLuint32 dataUsed*/);
+
+ static void _buffer_callbacks(
+ SLAndroidSimpleBufferQueueItf queueItf,
+ /*SLuint32 eventFlags,
+ const void * pBuffer,
+ SLuint32 bufferSize,
+ SLuint32 dataUsed,*/
+ void *pContext);
+public:
+
+ void set_singleton();
+
+ virtual const char* get_name() const;
+
+ virtual Error init();
+ virtual void start();
+ virtual int get_mix_rate() const ;
+ virtual OutputFormat get_output_format() const;
+ virtual void lock();
+ virtual void unlock();
+ virtual void finish();
+
+
+ AudioDriverAndroid();
+};
+
+#endif // AUDIO_DRIVER_ANDROID_H
+#endif
diff --git a/platform/android/audio_driver_jandroid.cpp b/platform/android/audio_driver_jandroid.cpp
new file mode 100644
index 0000000000..6e3f6f9505
--- /dev/null
+++ b/platform/android/audio_driver_jandroid.cpp
@@ -0,0 +1,248 @@
+/*************************************************************************/
+/* audio_driver_jandroid.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "audio_driver_jandroid.h"
+#include "globals.h"
+#include "os/os.h"
+#include "thread_jandroid.h"
+#ifndef ANDROID_NATIVE_ACTIVITY
+
+AudioDriverAndroid* AudioDriverAndroid::s_ad=NULL;
+
+jobject AudioDriverAndroid::io;
+jmethodID AudioDriverAndroid::_init_audio;
+jmethodID AudioDriverAndroid::_write_buffer;
+jmethodID AudioDriverAndroid::_quit;
+jmethodID AudioDriverAndroid::_pause;
+bool AudioDriverAndroid::active=false;
+jclass AudioDriverAndroid::cls;
+int AudioDriverAndroid::audioBufferFrames=0;
+int AudioDriverAndroid::mix_rate=44100;
+bool AudioDriverAndroid::quit=false;
+jobject AudioDriverAndroid::audioBuffer = NULL;
+void* AudioDriverAndroid::audioBufferPinned = NULL;
+Mutex *AudioDriverAndroid::mutex=NULL;
+int32_t* AudioDriverAndroid::audioBuffer32=NULL;
+
+
+const char* AudioDriverAndroid::get_name() const {
+
+ return "Android";
+}
+
+
+Error AudioDriverAndroid::init(){
+
+ mutex = Mutex::create();
+/*
+ // TODO: pass in/return a (Java) device ID, also whether we're opening for input or output
+ this->spec.samples = Android_JNI_OpenAudioDevice(this->spec.freq, this->spec.format == AUDIO_U8 ? 0 : 1, this->spec.channels, this->spec.samples);
+ SDL_CalculateAudioSpec(&this->spec);
+
+ if (this->spec.samples == 0) {
+ // Init failed?
+ SDL_SetError("Java-side initialization failed!");
+ return 0;
+ }
+*/
+
+// Android_JNI_SetupThread();
+
+
+ // __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device");
+
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ int mix_rate = GLOBAL_DEF("audio/mix_rate",44100);
+
+ int latency = GLOBAL_DEF("audio/output_latency",25);
+ latency=50;
+ unsigned int buffer_size = nearest_power_of_2( latency * mix_rate / 1000 );
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ print_line("audio buffer size: "+itos(buffer_size));
+ }
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","Initializing audio! params: %i,%i ",mix_rate,buffer_size);
+ audioBuffer = env->CallObjectMethod(io,_init_audio, mix_rate, buffer_size);
+
+
+ ERR_FAIL_COND_V( audioBuffer == NULL, ERR_INVALID_PARAMETER);
+
+ audioBuffer = env->NewGlobalRef(audioBuffer);
+
+ jboolean isCopy = JNI_FALSE;
+ audioBufferPinned = env->GetShortArrayElements((jshortArray)audioBuffer, &isCopy);
+ audioBufferFrames = env->GetArrayLength((jshortArray)audioBuffer);
+ audioBuffer32 = memnew_arr(int32_t,audioBufferFrames);
+
+ return OK;
+}
+
+void AudioDriverAndroid::start(){
+ active=true;
+
+}
+
+void AudioDriverAndroid::setup( jobject p_io) {
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ io=p_io;
+
+ jclass c = env->GetObjectClass(io);
+ cls = (jclass)env->NewGlobalRef(c);
+
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","starting to attempt get methods");
+
+ _init_audio = env->GetMethodID(cls, "audioInit", "(II)Ljava/lang/Object;");
+ if(_init_audio != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _init_audio ok!!");
+ } else {
+ __android_log_print(ANDROID_LOG_INFO,"godot","audioinit ok!");
+ }
+
+ _write_buffer = env->GetMethodID(cls, "audioWriteShortBuffer", "([S)V");
+ if(_write_buffer != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _write_buffer ok!!");
+ }
+
+
+ _quit = env->GetMethodID(cls, "audioQuit", "()V");
+ if(_quit != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _quit ok!!");
+ }
+
+ _pause = env->GetMethodID(cls, "audioPause", "(Z)V");
+ if(_quit != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _pause ok!!");
+ }
+
+
+}
+
+void AudioDriverAndroid::thread_func(JNIEnv *env) {
+
+ jclass cls = env->FindClass("com/android/godot/Godot");
+ if (cls) {
+
+ cls=(jclass)env->NewGlobalRef(cls);
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******CLASS FOUND!!!");
+ }
+ jfieldID fid = env->GetStaticFieldID(cls, "io", "Lcom/android/godot/GodotIO;");
+ jobject ob = env->GetStaticObjectField(cls,fid);
+ jobject gob = env->NewGlobalRef(ob);
+ jclass c = env->GetObjectClass(gob);
+ jclass lcls = (jclass)env->NewGlobalRef(c);
+ _write_buffer = env->GetMethodID(lcls, "audioWriteShortBuffer", "([S)V");
+ if(_write_buffer != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _write_buffer ok!!");
+ }
+
+ while(!quit) {
+
+
+ int16_t* ptr = (int16_t*)audioBufferPinned;
+ int fc = audioBufferFrames;
+
+ if (!s_ad->active || mutex->try_lock()!=OK) {
+
+ for(int i=0;i<fc;i++) {
+ ptr[i]=0;
+ }
+
+ } else {
+
+
+ s_ad->audio_server_process(fc/2,audioBuffer32);
+
+ mutex->unlock();
+
+ for(int i=0;i<fc;i++) {
+
+ ptr[i]=audioBuffer32[i]>>16;
+ }
+
+ }
+ env->ReleaseShortArrayElements((jshortArray)audioBuffer, (jshort *)ptr, JNI_COMMIT);
+ env->CallVoidMethod(gob, _write_buffer, (jshortArray)audioBuffer);
+ }
+
+
+
+}
+
+int AudioDriverAndroid::get_mix_rate() const {
+
+ return mix_rate;
+}
+AudioDriverSW::OutputFormat AudioDriverAndroid::get_output_format() const{
+
+ return OUTPUT_STEREO;
+}
+void AudioDriverAndroid::lock(){
+
+ if (mutex)
+ mutex->lock();
+
+}
+void AudioDriverAndroid::unlock() {
+
+ if (mutex)
+ mutex->unlock();
+}
+void AudioDriverAndroid::finish(){
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ env->CallVoidMethod(io, _quit);
+
+ if (audioBuffer) {
+ env->DeleteGlobalRef(audioBuffer);
+ audioBuffer = NULL;
+ audioBufferPinned = NULL;
+ }
+
+ active=false;
+}
+
+void AudioDriverAndroid::set_pause(bool p_pause) {
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ env->CallVoidMethod(io, _pause,p_pause);
+
+}
+
+AudioDriverAndroid::AudioDriverAndroid()
+{
+ s_ad=this;
+ active=false;
+
+
+
+}
+
+#endif
diff --git a/platform/android/audio_driver_jandroid.h b/platform/android/audio_driver_jandroid.h
new file mode 100644
index 0000000000..f102acf154
--- /dev/null
+++ b/platform/android/audio_driver_jandroid.h
@@ -0,0 +1,82 @@
+/*************************************************************************/
+/* audio_driver_jandroid.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef AUDIO_DRIVER_ANDROID_H
+#define AUDIO_DRIVER_ANDROID_H
+
+#include "servers/audio/audio_server_sw.h"
+#ifndef ANDROID_NATIVE_ACTIVITY
+
+#include "java_glue.h"
+
+class AudioDriverAndroid : public AudioDriverSW {
+
+
+ static Mutex *mutex;
+ static AudioDriverAndroid* s_ad;
+ static jobject io;
+ static jmethodID _init_audio;
+ static jmethodID _write_buffer;
+ static jmethodID _quit;
+ static jmethodID _pause;
+ static bool active;
+ static bool quit;
+
+ static jclass cls;
+
+ static jobject audioBuffer;
+ static void* audioBufferPinned;
+ static int32_t* audioBuffer32;
+ static int audioBufferFrames;
+ static int mix_rate;
+
+
+public:
+
+ void set_singleton();
+
+ virtual const char* get_name() const;
+
+ virtual Error init();
+ virtual void start();
+ virtual int get_mix_rate() const ;
+ virtual OutputFormat get_output_format() const;
+ virtual void lock();
+ virtual void unlock();
+ virtual void finish();
+
+ virtual void set_pause(bool p_pause);
+
+ static void setup( jobject act);
+ static void thread_func(JNIEnv *env);
+
+ AudioDriverAndroid();
+};
+
+#endif
+#endif // AUDIO_DRIVER_ANDROID_H
diff --git a/platform/android/detect.py b/platform/android/detect.py
new file mode 100644
index 0000000000..b89024a81a
--- /dev/null
+++ b/platform/android/detect.py
@@ -0,0 +1,175 @@
+import os
+import sys
+import string
+import platform
+
+def is_active():
+ return True
+
+def get_name():
+ return "Android"
+
+def can_build():
+
+ import os
+ if (not os.environ.has_key("ANDROID_NDK_ROOT")):
+ return False
+ return True
+
+def get_opts():
+
+ return [
+ ('ANDROID_NDK_ROOT', 'the path to Android NDK', os.environ.get("ANDROID_NDK_ROOT", 0)),
+ ('NDK_TOOLCHAIN', 'toolchain to use for the NDK',"arm-eabi-4.4.0"),
+ #android 2.3
+ ('ndk_platform', 'compile for platform: (2.2,2.3)',"2.2"),
+ ('NDK_TARGET', 'toolchain to use for the NDK',"arm-linux-androideabi-4.7"),
+ ('android_stl','enable STL support in android port (for modules)','no'),
+ ('armv6','compile for older phones running arm v6 (instead of v7+neon+smp)','no')
+
+ ]
+
+def get_flags():
+
+ return [
+ ('lua', 'no'),
+ ('tools', 'no'),
+ ('nedmalloc', 'no'),
+ ('builtin_zlib', 'no'),
+ ]
+
+
+def create(env):
+ tools = env['TOOLS']
+ if "mingw" in tools:
+ tools.remove('mingw')
+ if "applelink" in tools:
+ tools.remove("applelink")
+ env.Tool('gcc')
+ return env.Clone(tools=tools);
+
+def configure(env):
+
+ if env['PLATFORM'] == 'win32':
+ import methods
+ env.Tool('gcc')
+ env['SPAWN'] = methods.win32_spawn
+
+ ndk_platform=""
+
+ if (env["ndk_platform"]=="2.2"):
+ ndk_platform="android-8"
+ else:
+ ndk_platform="android-9"
+ env.Append(CPPFLAGS=["-DANDROID_NATIVE_ACTIVITY"])
+
+ print("Godot Android!!!!!")
+
+ env.Append(CPPPATH=['#platform/android'])
+
+ env['OBJSUFFIX'] = ".android.o"
+ env['LIBSUFFIX'] = ".android.a"
+ env['PROGSUFFIX'] = ".android"
+ env['SHLIBSUFFIX'] = ".so"
+
+ gcc_path=env["ANDROID_NDK_ROOT"]+"/toolchains/"+env["NDK_TARGET"]+"/prebuilt/";
+
+ import os
+ if (sys.platform.find("linux")==0):
+ if (platform.architecture()[0]=='64bit' or os.path.isdir(gcc_path+"linux-x86_64/bin")): # check was not working
+ gcc_path=gcc_path+"/linux-x86_64/bin"
+ else:
+ gcc_path=gcc_path+"/linux-x86/bin"
+ elif (sys.platform=="darwin"):
+ gcc_path=gcc_path+"/darwin-x86_64/bin" #this may be wrong
+ env['SHLINKFLAGS'][1] = '-shared'
+ elif (os.name=="nt"):
+ gcc_path=gcc_path+"/windows/bin" #this may be wrong
+
+
+
+ env['ENV']['PATH'] = gcc_path+":"+env['ENV']['PATH']
+
+ env['CC'] = gcc_path+'/arm-linux-androideabi-gcc'
+ env['CXX'] = gcc_path+'/arm-linux-androideabi-g++'
+ env['AR'] = gcc_path+"/arm-linux-androideabi-ar"
+ env['RANLIB'] = gcc_path+"/arm-linux-androideabi-ranlib"
+ env['AS'] = gcc_path+"/arm-linux-androideabi-as"
+
+ import string
+ #include path
+ gcc_include=env["ANDROID_NDK_ROOT"]+"/platforms/"+ndk_platform+"/arch-arm/usr/include"
+ ld_sysroot=env["ANDROID_NDK_ROOT"]+"/platforms/"+ndk_platform+"/arch-arm"
+ #glue_include=env["ANDROID_NDK_ROOT"]+"/sources/android/native_app_glue"
+ ld_path=env["ANDROID_NDK_ROOT"]+"/platforms/"+ndk_platform+"/arch-arm/usr/lib"
+ env.Append(CPPPATH=[gcc_include])
+# env['CCFLAGS'] = string.split('-DNO_THREADS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -fno-exceptions -mthumb -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED ')
+ print("********* armv6", env['armv6'])
+ if env["armv6"]!="no":
+ env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -D__ARM_ARCH_6__ -D__GLIBC__ -Wno-psabi -march=armv6 -mfpu=vfp -mfloat-abi=softfp -funsafe-math-optimizations -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED -DGLES1_ENABLED')
+ else:
+ env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -D__ARM_ARCH_7__ -D__GLIBC__ -Wno-psabi -march=armv6 -mfpu=neon -mfloat-abi=softfp -ftree-vectorize -funsafe-math-optimizations -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED -DGLES1_ENABLED')
+
+ env.Append(LDPATH=[ld_path])
+# env.Append(LIBS=['c','m','stdc++','log','EGL','GLESv1_CM','GLESv2','OpenSLES','supc++','android'])
+ if (env["ndk_platform"]!="2.2"):
+ env.Append(LIBS=['EGL','OpenSLES','android'])
+ env.Append(LIBS=['c','m','stdc++','log','GLESv1_CM','GLESv2', 'z'])
+
+ env["LINKFLAGS"]= string.split(" -g --sysroot="+ld_sysroot+" -Wl,--no-undefined -Wl,-z,noexecstack ")
+ env.Append(LINKFLAGS=["-Wl,-soname,libgodot_android.so"])
+
+ if (env["target"]=="release"):
+
+ env.Append(CCFLAGS=['-O2', '-ffast-math','-fomit-frame-pointer'])
+ env['OBJSUFFIX'] = "_opt"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = "_opt"+env['LIBSUFFIX']
+
+ elif (env["target"]=="release_debug"):
+
+ env.Append(CCFLAGS=['-O2', '-ffast-math','-DDEBUG_ENABLED'])
+ env['OBJSUFFIX'] = "_optd"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = "_optd"+env['LIBSUFFIX']
+
+ elif (env["target"]=="profile"):
+
+ env.Append(CCFLAGS=['-O2', '-ffast-math','-fomit-frame-pointer', '-g1'])
+ env.Append(LIBPATH=['#platform/android/armeabi'])
+ env.Append(LIBS=['andprof'])
+ env['OBJSUFFIX'] = "_prof"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = "_prof"+env['LIBSUFFIX']
+ env['SHLIBSUFFIX'] = "_prof"+env['SHLIBSUFFIX']
+
+ elif (env["target"]=="debug"):
+
+ env.Append(CCFLAGS=['-D_DEBUG', '-g1', '-Wall', '-O0', '-DDEBUG_ENABLED'])
+ env.Append(CPPFLAGS=['-DDEBUG_MEMORY_ALLOC'])
+
+ if env["armv6"] == "no":
+ env['neon_enabled']=True
+ env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED', '-DNO_FCNTL','-DMPC_FIXED_POINT'])
+# env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED','-DMPC_FIXED_POINT'])
+ if (env['android_stl']=='yes'):
+ #env.Append(CCFLAGS=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/system/include"])
+ env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.4.3/include"])
+ env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.4.3/libs/armeabi/include"])
+ env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.4.3/libs/armeabi"])
+ env.Append(LIBS=["gnustl_static","supc++"])
+ env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cpufeatures"])
+
+ #env.Append(CCFLAGS=["-I"+env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/stlport/stlport"])
+ #env.Append(CCFLAGS=["-I"+env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/libs/armeabi/include"])
+ #env.Append(LINKFLAGS=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/libs/armeabi/libstdc++.a"])
+ else:
+
+ env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gabi++/include"])
+ env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cpufeatures"])
+ env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gabi++/libs/armeabi"])
+ env.Append(LIBS=['gabi++_static'])
+ env.Append(CCFLAGS=["-fno-exceptions",'-DNO_SAFE_CAST'])
+
+ import methods
+ env.Append( BUILDERS = { 'GLSL120' : env.Builder(action = methods.build_legacygl_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
+ env.Append( BUILDERS = { 'GLSL' : env.Builder(action = methods.build_glsl_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
+ env.Append( BUILDERS = { 'GLSL120GLES' : env.Builder(action = methods.build_gles2_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
+
diff --git a/platform/android/dir_access_android.cpp b/platform/android/dir_access_android.cpp
new file mode 100644
index 0000000000..60bde61fc4
--- /dev/null
+++ b/platform/android/dir_access_android.cpp
@@ -0,0 +1,189 @@
+/*************************************************************************/
+/* dir_access_android.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifdef ANDROID_NATIVE_ACTIVITY
+#include "dir_access_android.h"
+#include "file_access_android.h"
+
+
+
+DirAccess *DirAccessAndroid::create_fs() {
+
+ return memnew(DirAccessAndroid);
+}
+
+bool DirAccessAndroid::list_dir_begin() {
+
+ list_dir_end();
+
+ AAssetDir* aad = AAssetManager_openDir(FileAccessAndroid::asset_manager,current_dir.utf8().get_data());
+ if (!aad)
+ return true; //nothing
+
+
+ return false;
+}
+
+String DirAccessAndroid::get_next(){
+
+ const char* fn= AAssetDir_getNextFileName(aad);
+ if (!fn)
+ return "";
+ String s;
+ s.parse_utf8(fn);
+ current=s;
+ return s;
+
+
+}
+bool DirAccessAndroid::current_is_dir() const{
+
+ String sd;
+ if (current_dir=="")
+ sd=current;
+ else
+ sd=current_dir+"/"+current;
+
+ AAssetDir* aad2 = AAssetManager_openDir(FileAccessAndroid::asset_manager,sd.utf8().get_data());
+ if (aad2) {
+
+ AAssetDir_close(aad2);
+ return true;
+ }
+
+ return false;
+
+}
+void DirAccessAndroid::list_dir_end(){
+
+ if (aad==NULL)
+ return;
+
+ AAssetDir_close(aad);
+ aad=NULL;
+
+}
+
+int DirAccessAndroid::get_drive_count(){
+
+ return 0;
+}
+String DirAccessAndroid::get_drive(int p_drive){
+
+ return "";
+}
+
+Error DirAccessAndroid::change_dir(String p_dir){
+
+ p_dir=p_dir.simplify_path();
+
+ if (p_dir=="" || p_dir=="." || (p_dir==".." && current_dir==""))
+ return OK;
+
+ String new_dir;
+
+ if (p_dir.begins_with("/"))
+ new_dir=p_dir.substr(1,p_dir.length());
+ else if (p_dir.begins_with("res://"))
+ new_dir=p_dir.substr(6,p_dir.length());
+ else //relative
+ new_dir=new_dir+"/"+p_dir;
+
+//test if newdir exists
+ new_dir=new_dir.simplify_path();
+
+ AAssetDir* aad = AAssetManager_openDir(FileAccessAndroid::asset_manager,new_dir.utf8().get_data());
+ if (aad) {
+
+ current_dir=new_dir;
+ AAssetDir_close(aad);
+ return OK;
+ }
+
+ return ERR_INVALID_PARAMETER;
+}
+
+String DirAccessAndroid::get_current_dir(){
+
+ return "/"+current_dir;
+}
+
+
+bool DirAccessAndroid::file_exists(String p_file){
+
+ String sd;
+ if (current_dir=="")
+ sd=p_file;
+ else
+ sd=current_dir+"/"+p_file;
+
+ AAsset *a=AAssetManager_open(FileAccessAndroid::asset_manager,sd.utf8().get_data(),AASSET_MODE_STREAMING);
+ if (a) {
+ AAsset_close(a);
+ return true;
+ }
+
+ return false;
+}
+
+
+Error DirAccessAndroid::make_dir(String p_dir){
+
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+}
+
+Error DirAccessAndroid::rename(String p_from, String p_to){
+
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+}
+Error DirAccessAndroid::remove(String p_name){
+
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+}
+
+//FileType get_file_type() const;
+size_t DirAccessAndroid::get_space_left() {
+
+ return 0;
+}
+
+void DirAccessAndroid::make_default() {
+
+ instance_func=create_fs;
+}
+
+DirAccessAndroid::DirAccessAndroid() {
+
+ aad=NULL;
+}
+
+DirAccessAndroid::~DirAccessAndroid() {
+
+ list_dir_end();;
+}
+#endif
diff --git a/platform/android/dir_access_android.h b/platform/android/dir_access_android.h
new file mode 100644
index 0000000000..a6aead6eb3
--- /dev/null
+++ b/platform/android/dir_access_android.h
@@ -0,0 +1,82 @@
+/*************************************************************************/
+/* dir_access_android.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef DIR_ACCESS_ANDROID_H
+#define DIR_ACCESS_ANDROID_H
+
+#ifdef ANDROID_NATIVE_ACTIVITY
+
+#include "os/dir_access.h"
+#include <stdio.h>
+#include <android/asset_manager.h>
+#include <android/log.h>
+#include <android_native_app_glue.h>
+
+
+
+class DirAccessAndroid : public DirAccess {
+
+ AAssetDir* aad;
+ String current_dir;
+ String current;
+
+ static DirAccess *create_fs();
+
+public:
+
+ virtual bool list_dir_begin(); ///< This starts dir listing
+ virtual String get_next();
+ virtual bool current_is_dir() const;
+ virtual void list_dir_end(); ///<
+
+ virtual int get_drive_count();
+ virtual String get_drive(int p_drive);
+
+ virtual Error change_dir(String p_dir); ///< can be relative or absolute, return false on success
+ virtual String get_current_dir(); ///< return current dir location
+
+
+ virtual bool file_exists(String p_file);
+
+
+ virtual Error make_dir(String p_dir);
+
+ virtual Error rename(String p_from, String p_to);
+ virtual Error remove(String p_name);
+
+ //virtual FileType get_file_type() const;
+ size_t get_space_left();
+
+ static void make_default();
+
+ DirAccessAndroid();
+ ~DirAccessAndroid();
+};
+
+#endif
+#endif // DIR_ACCESS_ANDROID_H
diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp
new file mode 100644
index 0000000000..0c8a5785f8
--- /dev/null
+++ b/platform/android/dir_access_jandroid.cpp
@@ -0,0 +1,241 @@
+/*************************************************************************/
+/* dir_access_jandroid.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef ANDROID_NATIVE_ACTIVITY
+
+#include "dir_access_jandroid.h"
+#include "file_access_jandroid.h"
+#include "thread_jandroid.h"
+jobject DirAccessJAndroid::io=NULL;
+jclass DirAccessJAndroid::cls=NULL;
+jmethodID DirAccessJAndroid::_dir_open=NULL;
+jmethodID DirAccessJAndroid::_dir_next=NULL;
+jmethodID DirAccessJAndroid::_dir_close=NULL;
+
+
+DirAccess *DirAccessJAndroid::create_fs() {
+
+ return memnew(DirAccessJAndroid);
+}
+
+bool DirAccessJAndroid::list_dir_begin() {
+
+ list_dir_end();
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ jstring js = env->NewStringUTF(current_dir.utf8().get_data());
+ int res = env->CallIntMethod(io,_dir_open,js);
+ if (res<=0)
+ return true;
+
+ id=res;
+
+ return false;
+}
+
+String DirAccessJAndroid::get_next(){
+
+ ERR_FAIL_COND_V(id==0,"");
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ jstring str= (jstring)env->CallObjectMethod(io,_dir_next,id);
+ if (!str)
+ return "";
+
+ int sl = env->GetStringLength(str);
+ if (sl==0) {
+ env->DeleteLocalRef((jobject)str);
+ return "";
+ }
+
+ CharString cs;
+ cs.resize(sl+1);
+ env->GetStringRegion(str,0,sl,(jchar*)&cs[0]);
+ cs[sl]=0;
+
+ String ret;
+ ret.parse_utf8(&cs[0]);
+ env->DeleteLocalRef((jobject)str);
+
+ return ret;
+
+}
+bool DirAccessJAndroid::current_is_dir() const{
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ String sd;
+ if (current_dir=="")
+ sd=current;
+ else
+ sd=current_dir+"/"+current;
+
+ jstring js = env->NewStringUTF(sd.utf8().get_data());
+
+ int res = env->CallIntMethod(io,_dir_open,js);
+ if (res<=0)
+ return false;
+
+ env->CallObjectMethod(io,_dir_close,res);
+
+
+ return true;
+}
+void DirAccessJAndroid::list_dir_end(){
+
+ if (id==0)
+ return;
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ env->CallObjectMethod(io,_dir_close,id);
+ id=0;
+
+
+}
+
+int DirAccessJAndroid::get_drive_count(){
+
+ return 0;
+}
+String DirAccessJAndroid::get_drive(int p_drive){
+
+ return "";
+}
+
+Error DirAccessJAndroid::change_dir(String p_dir){
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ p_dir=p_dir.simplify_path();
+
+ if (p_dir=="" || p_dir=="." || (p_dir==".." && current_dir==""))
+ return OK;
+
+ String new_dir;
+
+ if (p_dir.begins_with("/"))
+ new_dir=p_dir.substr(1,p_dir.length());
+ else if (p_dir.begins_with("res://"))
+ new_dir=p_dir.substr(6,p_dir.length());
+ else //relative
+ new_dir=new_dir+"/"+p_dir;
+
+//test if newdir exists
+ new_dir=new_dir.simplify_path();
+
+ jstring js = env->NewStringUTF(new_dir.utf8().get_data());
+ int res = env->CallIntMethod(io,_dir_open,js);
+ if (res<=0)
+ return ERR_INVALID_PARAMETER;
+
+ env->CallObjectMethod(io,_dir_close,res);
+
+
+
+ return OK;
+}
+
+String DirAccessJAndroid::get_current_dir(){
+
+ return "/"+current_dir;
+}
+
+bool DirAccessJAndroid::file_exists(String p_file){
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ String sd;
+ if (current_dir=="")
+ sd=p_file;
+ else
+ sd=current_dir+"/"+p_file;
+
+ FileAccessJAndroid *f = memnew(FileAccessJAndroid);
+ bool exists = f->file_exists(sd);
+ memdelete(f);
+
+ return exists;
+}
+
+
+Error DirAccessJAndroid::make_dir(String p_dir){
+
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+}
+
+Error DirAccessJAndroid::rename(String p_from, String p_to){
+
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+}
+Error DirAccessJAndroid::remove(String p_name){
+
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+}
+
+//FileType get_file_type() const;
+size_t DirAccessJAndroid::get_space_left() {
+
+ return 0;
+}
+
+
+void DirAccessJAndroid::setup( jobject p_io) {
+
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ io=p_io;
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP7");
+
+ jclass c = env->GetObjectClass(io);
+ cls = (jclass)env->NewGlobalRef(c);
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP8");
+
+ _dir_open = env->GetMethodID(cls, "dir_open", "(Ljava/lang/String;)I");
+ if(_dir_open != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _dir_open ok!!");
+ }
+ _dir_next = env->GetMethodID(cls, "dir_next", "(I)Ljava/lang/String;");
+ if(_dir_next != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _dir_next ok!!");
+ }
+ _dir_close = env->GetMethodID(cls, "dir_close", "(I)V");
+ if(_dir_close != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _dir_close ok!!");
+ }
+
+// (*env)->CallVoidMethod(env,obj,aMethodID, myvar);
+}
+
+
+DirAccessJAndroid::DirAccessJAndroid() {
+
+ id=0;
+}
+
+DirAccessJAndroid::~DirAccessJAndroid() {
+
+ list_dir_end();;
+}
+#endif
diff --git a/platform/android/dir_access_jandroid.h b/platform/android/dir_access_jandroid.h
new file mode 100644
index 0000000000..b6e3fe393f
--- /dev/null
+++ b/platform/android/dir_access_jandroid.h
@@ -0,0 +1,90 @@
+/*************************************************************************/
+/* dir_access_jandroid.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef DIR_ACCESS_JANDROID_H
+#define DIR_ACCESS_JANDROID_H
+
+#ifndef ANDROID_NATIVE_ACTIVITY
+
+
+#include "java_glue.h"
+#include "os/dir_access.h"
+#include <stdio.h>
+
+
+class DirAccessJAndroid : public DirAccess {
+
+ //AAssetDir* aad;
+
+ static jobject io;
+ static jclass cls;
+
+ static jmethodID _dir_open;
+ static jmethodID _dir_next;
+ static jmethodID _dir_close;
+
+ int id;
+
+ String current_dir;
+ String current;
+
+ static DirAccess *create_fs();
+
+public:
+
+ virtual bool list_dir_begin(); ///< This starts dir listing
+ virtual String get_next();
+ virtual bool current_is_dir() const;
+ virtual void list_dir_end(); ///<
+
+ virtual int get_drive_count();
+ virtual String get_drive(int p_drive);
+
+ virtual Error change_dir(String p_dir); ///< can be relative or absolute, return false on success
+ virtual String get_current_dir(); ///< return current dir location
+
+
+ virtual bool file_exists(String p_file);
+
+ virtual Error make_dir(String p_dir);
+
+ virtual Error rename(String p_from, String p_to);
+ virtual Error remove(String p_name);
+
+ //virtual FileType get_file_type() const;
+ size_t get_space_left();
+
+
+ static void setup( jobject io);
+
+ DirAccessJAndroid();
+ ~DirAccessJAndroid();
+};
+
+#endif // DIR_ACCESS_JANDROID_H
+#endif
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
new file mode 100644
index 0000000000..a9b96a116b
--- /dev/null
+++ b/platform/android/export/export.cpp
@@ -0,0 +1,1229 @@
+#include "version.h"
+#include "export.h"
+#include "tools/editor/editor_settings.h"
+#include "tools/editor/editor_import_export.h"
+#include "tools/editor/editor_node.h"
+#include "io/zip_io.h"
+#include "io/marshalls.h"
+#include "globals.h"
+#include "os/file_access.h"
+#include "os/os.h"
+#include "platform/android/logo.h"
+
+class EditorExportPlatformAndroid : public EditorExportPlatform {
+
+ OBJ_TYPE( EditorExportPlatformAndroid,EditorExportPlatform );
+
+ String custom_release_package;
+ String custom_debug_package;
+
+ int version_code;
+ String version_name;
+ String package;
+ String name;
+ String icon;
+ bool _signed;
+ int orientation;
+
+ String release_keystore;
+ String release_username;
+
+ struct APKExportData {
+
+ zipFile apk;
+ EditorProgress *ep;
+ };
+
+ struct Device {
+
+ String id;
+ String name;
+ String description;
+ };
+
+ Vector<Device> devices;
+ bool devices_changed;
+ Mutex *device_lock;
+ Thread *device_thread;
+ Ref<ImageTexture> logo;
+
+ volatile bool quit_request;
+
+
+ static void _device_poll_thread(void *ud);
+
+ String get_project_name() const;
+ void _fix_manifest(Vector<uint8_t>& p_manifest);
+ void _fix_resources(Vector<uint8_t>& p_manifest);
+ static Error save_apk_file(void *p_userdata,const String& p_path, const Vector<uint8_t>& p_data,int p_file,int p_total);
+
+protected:
+
+ bool _set(const StringName& p_name, const Variant& p_value);
+ bool _get(const StringName& p_name,Variant &r_ret) const;
+ void _get_property_list( List<PropertyInfo> *p_list) const;
+
+public:
+
+ virtual String get_name() const { return "Android"; }
+ virtual ImageCompression get_image_compression() const { return IMAGE_COMPRESSION_ETC1; }
+ virtual Ref<Texture> get_logo() const { return logo; }
+
+
+ virtual bool poll_devices();
+ virtual int get_device_count() const;
+ virtual String get_device_name(int p_device) const;
+ virtual String get_device_info(int p_device) const;
+ virtual Error run(int p_device);
+
+ virtual bool requieres_password(bool p_debug) const { return !p_debug; }
+ virtual String get_binary_extension() const { return "apk"; }
+ virtual Error export_project(const String& p_path,bool p_debug,const String& p_password="");
+
+ virtual bool can_export(String *r_error=NULL) const;
+
+ EditorExportPlatformAndroid();
+ ~EditorExportPlatformAndroid();
+};
+
+bool EditorExportPlatformAndroid::_set(const StringName& p_name, const Variant& p_value) {
+
+ String n=p_name;
+
+ if (n=="version/code")
+ version_code=p_value;
+ else if (n=="version/name")
+ version_name=p_value;
+ else if (n=="package/unique_name")
+ package=p_value;
+ else if (n=="package/name")
+ name=p_value;
+ else if (n=="package/icon")
+ icon=p_value;
+ else if (n=="package/signed")
+ _signed=p_value;
+ else if (n=="screen/orientation")
+ orientation=p_value;
+ else if (n=="keystore/release")
+ release_keystore=p_value;
+ else if (n=="keystore/release_user")
+ release_username=p_value;
+ else
+ return false;
+
+ return true;
+}
+
+bool EditorExportPlatformAndroid::_get(const StringName& p_name,Variant &r_ret) const{
+
+ String n=p_name;
+
+ if (n=="version/code")
+ r_ret=version_code;
+ else if (n=="version/name")
+ r_ret=version_name;
+ else if (n=="package/unique_name")
+ r_ret=package;
+ else if (n=="package/name")
+ r_ret=name;
+ else if (n=="package/icon")
+ r_ret=icon;
+ else if (n=="package/signed")
+ r_ret=_signed;
+ else if (n=="screen/orientation")
+ r_ret=orientation;
+ else if (n=="keystore/release")
+ r_ret=release_keystore;
+ else if (n=="keystore/release_user")
+ r_ret=release_username;
+ else
+ return false;
+
+ return true;
+}
+void EditorExportPlatformAndroid::_get_property_list( List<PropertyInfo> *p_list) const{
+
+ p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/debug", PROPERTY_HINT_FILE,"apk"));
+ p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/release", PROPERTY_HINT_FILE,"apk"));
+ p_list->push_back( PropertyInfo( Variant::INT, "version/code", PROPERTY_HINT_RANGE,"1,65535,1"));
+ p_list->push_back( PropertyInfo( Variant::STRING, "version/name") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "package/unique_name") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "package/name") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "package/icon",PROPERTY_HINT_FILE,"png") );
+ p_list->push_back( PropertyInfo( Variant::BOOL, "package/signed") );
+ p_list->push_back( PropertyInfo( Variant::INT, "screen/orientation",PROPERTY_HINT_ENUM,"Landscape,Portrait") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "keystore/release",PROPERTY_HINT_FILE,"keystore") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "keystore/release_user" ) );
+
+ //p_list->push_back( PropertyInfo( Variant::INT, "resources/pack_mode", PROPERTY_HINT_ENUM,"Copy,Single Exec.,Pack (.pck),Bundles (Optical)"));
+
+}
+
+
+static String _parse_string(const uint8_t *p_bytes,bool p_utf8) {
+
+ uint32_t offset=0;
+ uint32_t len = decode_uint16(&p_bytes[offset]);
+
+ if (p_utf8) {
+ //don't know how to read extended utf8, this will have to be for now
+ len>>=8;
+
+ }
+ offset+=2;
+ printf("len %i, unicode: %i\n",len,int(p_utf8));
+
+ if (p_utf8) {
+
+ Vector<uint8_t> str8;
+ str8.resize(len+1);
+ for(int i=0;i<len;i++) {
+ str8[i]=p_bytes[offset+i];
+ }
+ str8[len]=0;
+ String str;
+ str.parse_utf8((const char*)str8.ptr());
+ return str;
+ } else {
+
+ String str;
+ for(int i=0;i<len;i++) {
+ CharType c = decode_uint16(&p_bytes[offset+i*2]);
+ if (c==0)
+ break;
+ str += String::chr(c);
+ }
+ return str;
+ }
+
+}
+
+void EditorExportPlatformAndroid::_fix_resources(Vector<uint8_t>& p_manifest) {
+
+
+ const int UTF8_FLAG = 0x00000100;
+ print_line("*******************GORRRGLE***********************");
+
+ uint32_t header = decode_uint32(&p_manifest[0]);
+ uint32_t filesize = decode_uint32(&p_manifest[4]);
+ uint32_t string_block_len = decode_uint32(&p_manifest[16]);
+ uint32_t string_count = decode_uint32(&p_manifest[20]);
+ uint32_t string_flags = decode_uint32(&p_manifest[28]);
+ const uint32_t string_table_begins = 40;
+
+ Vector<String> string_table;
+
+ printf("stirng block len: %i\n",string_block_len);
+ printf("stirng count: %i\n",string_count);
+ printf("flags: %x\n",string_flags);
+
+ for(int i=0;i<string_count;i++) {
+
+ uint32_t offset = decode_uint32(&p_manifest[string_table_begins+i*4]);
+ offset+=string_table_begins+string_count*4;
+
+ String str = _parse_string(&p_manifest[offset],string_flags&UTF8_FLAG);
+
+ if (str.begins_with("godot-project-name")) {
+
+
+ if (str=="godot-project-name") {
+ //project name
+ str = get_project_name();
+
+ } else {
+
+ String lang = str.substr(str.find_last("-")+1,str.length()).replace("-","_");
+ String prop = "application/name_"+lang;
+ if (Globals::get_singleton()->has(prop)) {
+ str = Globals::get_singleton()->get(prop);
+ } else {
+ str = get_project_name();
+ }
+ }
+ }
+
+ string_table.push_back(str);
+
+ }
+
+ //write a new string table, but use 16 bits
+ Vector<uint8_t> ret;
+ ret.resize(string_table_begins+string_table.size()*4);
+
+ for(int i=0;i<string_table_begins;i++) {
+
+ ret[i]=p_manifest[i];
+ }
+
+ int ofs=0;
+ for(int i=0;i<string_table.size();i++) {
+
+ encode_uint32(ofs,&ret[string_table_begins+i*4]);
+ ofs+=string_table[i].length()*2+2+2;
+ }
+
+ ret.resize(ret.size()+ofs);
+ uint8_t *chars=&ret[ret.size()-ofs];
+ for(int i=0;i<string_table.size();i++) {
+
+ String s = string_table[i];
+ encode_uint16(s.length(),chars);
+ chars+=2;
+ for(int j=0;j<s.length();j++) {
+ encode_uint16(s[j],chars);
+ chars+=2;
+ }
+ encode_uint16(0,chars);
+ chars+=2;
+ }
+
+ //pad
+ while(ret.size()%4)
+ ret.push_back(0);
+
+ //change flags to not use utf8
+ encode_uint32(string_flags&~0x100,&ret[28]);
+ //change length
+ encode_uint32(ret.size()-12,&ret[16]);
+ //append the rest...
+ int rest_from = 12+string_block_len;
+ int rest_to = ret.size();
+ int rest_len = (p_manifest.size() - rest_from);
+ ret.resize(ret.size() + (p_manifest.size() - rest_from) );
+ for(int i=0;i<rest_len;i++) {
+ ret[rest_to+i]=p_manifest[rest_from+i];
+ }
+ //finally update the size
+ encode_uint32(ret.size(),&ret[4]);
+
+
+ p_manifest=ret;
+ printf("end\n");
+}
+
+String EditorExportPlatformAndroid::get_project_name() const {
+
+ String aname;
+ if (this->name!="") {
+ aname=this->name;
+ } else {
+ aname = Globals::get_singleton()->get("application/name");
+
+ }
+
+ if (aname=="") {
+ aname=_MKSTR(VERSION_NAME);
+ }
+
+ return aname;
+}
+
+
+void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest) {
+
+
+ const int CHUNK_AXML_FILE = 0x00080003;
+ const int CHUNK_RESOURCEIDS = 0x00080180;
+ const int CHUNK_STRINGS = 0x001C0001;
+ const int CHUNK_XML_END_NAMESPACE = 0x00100101;
+ const int CHUNK_XML_END_TAG = 0x00100103;
+ const int CHUNK_XML_START_NAMESPACE = 0x00100100;
+ const int CHUNK_XML_START_TAG = 0x00100102;
+ const int CHUNK_XML_TEXT = 0x00100104;
+ const int UTF8_FLAG = 0x00000100;
+
+ Vector<String> string_table;
+
+ uint32_t ofs=0;
+
+
+ uint32_t header = decode_uint32(&p_manifest[ofs]);
+ uint32_t filesize = decode_uint32(&p_manifest[ofs+4]);
+ ofs+=8;
+
+// print_line("FILESIZE: "+itos(filesize)+" ACTUAL: "+itos(p_manifest.size()));
+
+ uint32_t string_count;
+ uint32_t styles_count;
+ uint32_t string_flags;
+ uint32_t string_data_offset;
+
+ uint32_t styles_offset;
+ uint32_t string_table_begins;
+ uint32_t string_table_ends;
+ Vector<uint8_t> stable_extra;
+
+ while(ofs < p_manifest.size()) {
+
+ uint32_t chunk = decode_uint32(&p_manifest[ofs]);
+ uint32_t size = decode_uint32(&p_manifest[ofs+4]);
+
+
+ switch(chunk) {
+
+ case CHUNK_STRINGS: {
+
+
+ int iofs=ofs+8;
+
+ uint32_t string_count=decode_uint32(&p_manifest[iofs]);
+ uint32_t styles_count=decode_uint32(&p_manifest[iofs+4]);
+ uint32_t string_flags=decode_uint32(&p_manifest[iofs+8]);
+ uint32_t string_data_offset=decode_uint32(&p_manifest[iofs+12]);
+ uint32_t styles_offset=decode_uint32(&p_manifest[iofs+16]);
+/*
+ printf("string count: %i\n",string_count);
+ printf("flags: %i\n",string_flags);
+ printf("sdata ofs: %i\n",string_data_offset);
+ printf("styles ofs: %i\n",styles_offset);
+*/
+ uint32_t st_offset=iofs+20;
+ string_table.resize(string_count);
+ uint32_t string_end=0;
+
+ string_table_begins=st_offset;
+
+
+ for(int i=0;i<string_count;i++) {
+
+ uint32_t string_at = decode_uint32(&p_manifest[st_offset+i*4]);
+ string_at+=st_offset+string_count*4;
+
+ ERR_EXPLAIN("Unimplemented, can't read utf8 string table.");
+ ERR_FAIL_COND(string_flags&UTF8_FLAG);
+
+ if (string_flags&UTF8_FLAG) {
+
+
+
+ } else {
+ uint32_t len = decode_uint16(&p_manifest[string_at]);
+ Vector<CharType> ucstring;
+ ucstring.resize(len+1);
+ for(int j=0;j<len;j++) {
+ uint16_t c=decode_uint16(&p_manifest[string_at+2+2*j]);
+ ucstring[j]=c;
+ }
+ string_end=MAX(string_at+2+2*len,string_end);
+ ucstring[len]=0;
+ string_table[i]=ucstring.ptr();
+ }
+
+
+// print_line("String "+itos(i)+": "+string_table[i]);
+ }
+
+ for(int i=string_end;i<(ofs+size);i++) {
+ stable_extra.push_back(p_manifest[i]);
+ }
+
+// printf("stable extra: %i\n",int(stable_extra.size()));
+ string_table_ends=ofs+size;
+
+// print_line("STABLE SIZE: "+itos(size)+" ACTUAL: "+itos(string_table_ends));
+
+ } break;
+ case CHUNK_XML_START_TAG: {
+
+ int iofs=ofs+8;
+ uint32_t line=decode_uint32(&p_manifest[iofs]);
+ uint32_t nspace=decode_uint32(&p_manifest[iofs+8]);
+ uint32_t name=decode_uint32(&p_manifest[iofs+12]);
+ uint32_t check=decode_uint32(&p_manifest[iofs+16]);
+
+ String tname=string_table[name];
+
+// printf("NSPACE: %i\n",nspace);
+ //printf("NAME: %i (%s)\n",name,tname.utf8().get_data());
+ //printf("CHECK: %x\n",check);
+ uint32_t attrcount=decode_uint32(&p_manifest[iofs+20]);
+ iofs+=28;
+ //printf("ATTRCOUNT: %x\n",attrcount);
+ for(int i=0;i<attrcount;i++) {
+ uint32_t attr_nspace=decode_uint32(&p_manifest[iofs]);
+ uint32_t attr_name=decode_uint32(&p_manifest[iofs+4]);
+ uint32_t attr_value=decode_uint32(&p_manifest[iofs+8]);
+ uint32_t attr_flags=decode_uint32(&p_manifest[iofs+12]);
+ uint32_t attr_resid=decode_uint32(&p_manifest[iofs+16]);
+
+
+ String value;
+ if (attr_value!=0xFFFFFFFF)
+ value=string_table[attr_value];
+ else
+ value="Res #"+itos(attr_resid);
+ String attrname = string_table[attr_name];
+ String nspace;
+ if (attr_nspace!=0xFFFFFFFF)
+ nspace=string_table[attr_nspace];
+ else
+ nspace="";
+
+ printf("ATTR %i NSPACE: %i\n",i,attr_nspace);
+ printf("ATTR %i NAME: %i (%s)\n",i,attr_name,attrname.utf8().get_data());
+ printf("ATTR %i VALUE: %i (%s)\n",i,attr_value,value.utf8().get_data());
+ printf("ATTR %i FLAGS: %x\n",i,attr_flags);
+ printf("ATTR %i RESID: %x\n",i,attr_resid);
+
+ //replace project information
+ if (tname=="manifest" && attrname=="package") {
+
+ print_line("FOUND PACKAGE");
+ string_table[attr_value]=package;
+ }
+
+ //print_line("tname: "+tname);
+ //print_line("nspace: "+nspace);
+ //print_line("attrname: "+attrname);
+ if (tname=="manifest" && /*nspace=="android" &&*/ attrname=="versionCode") {
+
+ print_line("FOUND versioncode");
+ encode_uint32(version_code,&p_manifest[iofs+16]);
+ }
+
+
+ if (tname=="manifest" && /*nspace=="android" &&*/ attrname=="versionName") {
+
+ print_line("FOUND versionname");
+ if (attr_value==0xFFFFFFFF) {
+ WARN_PRINT("Version name in a resource, should be plaintext")
+ } else
+ string_table[attr_value]=version_name;
+ }
+
+ if (tname=="activity" && /*nspace=="android" &&*/ attrname=="screenOrientation") {
+
+ print_line("FOUND screen orientation");
+ if (attr_value==0xFFFFFFFF) {
+ WARN_PRINT("Version name in a resource, should be plaintext")
+ } else {
+ string_table[attr_value]=(orientation==0?"landscape":"portrait");
+ }
+ }
+
+ if (tname=="application" && /*nspace=="android" &&*/ attrname=="label") {
+
+ print_line("FOUND application");
+ if (attr_value==0xFFFFFFFF) {
+ WARN_PRINT("Application name in a resource, should be plaintext.")
+ } else {
+
+ String aname = get_project_name();
+ string_table[attr_value]=aname;
+ }
+ }
+ if (tname=="activity" && /*nspace=="android" &&*/ attrname=="label") {
+
+ print_line("FOUND activity name");
+ if (attr_value==0xFFFFFFFF) {
+ WARN_PRINT("Activity name in a resource, should be plaintext")
+ } else {
+ String aname;
+ if (this->name!="") {
+ aname=this->name;
+ } else {
+ aname = Globals::get_singleton()->get("application/name");
+
+ }
+
+ if (aname=="") {
+ aname=_MKSTR(VERSION_NAME);
+ }
+
+ print_line("APP NAME IS..."+aname);
+ string_table[attr_value]=aname;
+ }
+ }
+
+ iofs+=20;
+ }
+
+ } break;
+ }
+ printf("chunk %x: size: %d\n",chunk,size);
+
+ ofs+=size;
+ }
+
+ printf("end\n");
+
+ //create new andriodmanifest binary
+
+ Vector<uint8_t> ret;
+ ret.resize(string_table_begins+string_table.size()*4);
+
+ for(int i=0;i<string_table_begins;i++) {
+
+ ret[i]=p_manifest[i];
+ }
+
+ ofs=0;
+ for(int i=0;i<string_table.size();i++) {
+
+ encode_uint32(ofs,&ret[string_table_begins+i*4]);
+ ofs+=string_table[i].length()*2+2+2;
+ print_line("ofs: "+itos(i)+": "+itos(ofs));
+ }
+ ret.resize(ret.size()+ofs);
+ uint8_t *chars=&ret[ret.size()-ofs];
+ for(int i=0;i<string_table.size();i++) {
+
+ String s = string_table[i];
+ print_line("savint string :"+s);
+ encode_uint16(s.length(),chars);
+ chars+=2;
+ for(int j=0;j<s.length();j++) { //include zero?
+ encode_uint16(s[j],chars);
+ chars+=2;
+ }
+ encode_uint16(0,chars);
+ chars+=2;
+
+ }
+
+
+ ret.resize(ret.size()+stable_extra.size());
+ while(ret.size()%4)
+ ret.push_back(0);
+
+ for(int i=0;i<stable_extra.size();i++) {
+
+ chars[i]=stable_extra[i];
+ }
+
+
+ uint32_t new_stable_end=ret.size();
+
+ uint32_t extra = (p_manifest.size()-string_table_ends);
+ ret.resize(new_stable_end + extra);
+ for(int i=0;i<extra;i++)
+ ret[new_stable_end+i]=p_manifest[string_table_ends+i];
+
+ while(ret.size()%4)
+ ret.push_back(0);
+ encode_uint32(ret.size(),&ret[4]); //update new file size
+
+ encode_uint32(new_stable_end-8,&ret[12]); //update new string table size
+
+ print_line("file size: "+itos(ret.size()));
+
+ p_manifest=ret;
+
+
+
+
+
+
+#if 0
+ uint32_t header[9];
+ for(int i=0;i<9;i++) {
+ header[i]=decode_uint32(&p_manifest[i*4]);
+ }
+
+ print_line("STO: "+itos(header[3]));
+ uint32_t st_offset=9*4;
+ //ERR_FAIL_COND(header[3]!=0x24)
+ uint32_t string_count=header[4];
+
+
+ string_table.resize(string_count);
+
+ for(int i=0;i<string_count;i++) {
+
+ uint32_t string_at = decode_uint32(&p_manifest[st_offset+i*4]);
+ string_at+=st_offset+string_count*4;
+ uint32_t len = decode_uint16(&p_manifest[string_at]);
+ Vector<CharType> ucstring;
+ ucstring.resize(len+1);
+ for(int j=0;j<len;j++) {
+ uint16_t c=decode_uint16(&p_manifest[string_at+2+2*j]);
+ ucstring[j]=c;
+ }
+ ucstring[len]=0;
+ string_table[i]=ucstring.ptr();
+ }
+
+
+#endif
+
+}
+
+
+
+Error EditorExportPlatformAndroid::save_apk_file(void *p_userdata,const String& p_path, const Vector<uint8_t>& p_data,int p_file,int p_total) {
+
+ APKExportData *ed=(APKExportData*)p_userdata;
+ String dst_path=p_path;
+ dst_path=dst_path.replace_first("res://","assets/");
+
+ zipOpenNewFileInZip(ed->apk,
+ dst_path.utf8().get_data(),
+ NULL,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ Z_DEFLATED,
+ Z_DEFAULT_COMPRESSION);
+
+
+ zipWriteInFileInZip(ed->apk,p_data.ptr(),p_data.size());
+ zipCloseFileInZip(ed->apk);
+ ed->ep->step("File: "+p_path,3+p_file*100/p_total);
+ return OK;
+
+}
+
+
+
+Error EditorExportPlatformAndroid::export_project(const String& p_path,bool p_debug,const String& p_password) {
+
+ String src_apk;
+
+ EditorProgress ep("export","Exporting for Android",104);
+
+ String apk_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/";
+
+ if (p_debug) {
+
+ src_apk=custom_debug_package!=""?custom_debug_package:apk_path+"android_debug.apk";
+ } else {
+
+ src_apk=custom_release_package!=""?custom_release_package:apk_path+"android_release.apk";
+
+ }
+
+
+ FileAccess *src_f=NULL;
+ zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
+
+
+
+ ep.step("Creating APK",0);
+
+ unzFile pkg = unzOpen2(src_apk.utf8().get_data(), &io);
+ if (!pkg) {
+
+ EditorNode::add_io_error("Could not find template APK to export:\n"+src_apk);
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ ERR_FAIL_COND_V(!pkg, ERR_CANT_OPEN);
+ int ret = unzGoToFirstFile(pkg);
+
+ zlib_filefunc_def io2=io;
+ FileAccess *dst_f=NULL;
+ io2.opaque=&dst_f;
+ zipFile apk=zipOpen2(p_path.utf8().get_data(),APPEND_STATUS_CREATE,NULL,&io2);
+
+
+ while(ret==UNZ_OK) {
+
+ //get filename
+ unz_file_info info;
+ char fname[16384];
+ ret = unzGetCurrentFileInfo(pkg,&info,fname,16384,NULL,0,NULL,0);
+
+ String file=fname;
+
+ Vector<uint8_t> data;
+ data.resize(info.uncompressed_size);
+
+ //read
+ unzOpenCurrentFile(pkg);
+ unzReadCurrentFile(pkg,data.ptr(),data.size());
+ unzCloseCurrentFile(pkg);
+
+ //write
+
+ if (file=="AndroidManifest.xml") {
+
+ _fix_manifest(data);
+ }
+
+ if (file=="resources.arsc") {
+
+ _fix_resources(data);
+ }
+
+ if (file=="res/drawable/icon.png") {
+ bool found=false;
+
+ if (this->icon!="" && this->icon.ends_with(".png")) {
+
+ FileAccess *f = FileAccess::open(this->icon,FileAccess::READ);
+ if (f) {
+
+ data.resize(f->get_len());
+ f->get_buffer(data.ptr(),data.size());
+ memdelete(f);
+ found=true;
+ }
+
+ }
+
+ if (!found) {
+
+ String appicon = Globals::get_singleton()->get("application/icon");
+ if (appicon!="" && appicon.ends_with(".png")) {
+ FileAccess*f = FileAccess::open(appicon,FileAccess::READ);
+ if (f) {
+ data.resize(f->get_len());
+ f->get_buffer(data.ptr(),data.size());
+ memdelete(f);
+ }
+ }
+ }
+ }
+
+ print_line("ADDING: "+file);
+ zipOpenNewFileInZip(apk,
+ file.utf8().get_data(),
+ NULL,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ Z_DEFLATED,
+ Z_DEFAULT_COMPRESSION);
+
+ zipWriteInFileInZip(apk,data.ptr(),data.size());
+ zipCloseFileInZip(apk);
+
+ ret = unzGoToNextFile(pkg);
+ }
+
+
+ ep.step("Adding Files..",1);
+
+
+
+ APKExportData ed;
+ ed.ep=&ep;
+ ed.apk=apk;
+
+ Error err = export_project_files(save_apk_file,&ed,false);
+
+ zipClose(apk,NULL);
+ unzClose(pkg);
+
+ if (err) {
+ return err;
+ }
+
+
+
+ if (_signed) {
+
+
+ String jarsigner=EditorSettings::get_singleton()->get("android/jarsigner");
+ if (!FileAccess::exists(jarsigner)) {
+ EditorNode::add_io_error("'jarsigner' could not be found.\nPlease supply a path in the editor settings.\nResulting apk is unsigned.");
+ return OK;
+ }
+
+ String keystore;
+ String password;
+ String user;
+ if (p_debug) {
+ keystore=EditorSettings::get_singleton()->get("android/debug_keystore");
+ password=EditorSettings::get_singleton()->get("android/debug_keystore_pass");
+ user=EditorSettings::get_singleton()->get("android/debug_keystore_user");
+
+ ep.step("Signing Debug APK..",103);
+
+ } else {
+ keystore=release_keystore;
+ password=p_password;
+ user=release_username;
+
+ ep.step("Signing Release APK..",103);
+
+ }
+
+ if (!FileAccess::exists(keystore)) {
+ EditorNode::add_io_error("Could not find keytore, unable to export.");
+ return ERR_FILE_CANT_OPEN;
+ }
+
+ List<String> args;
+ args.push_back("-digestalg");
+ args.push_back("SHA1");
+ args.push_back("-sigalg");
+ args.push_back("MD5withRSA");
+ args.push_back("-verbose");
+ args.push_back("-keystore");
+ args.push_back(keystore);
+ args.push_back("-storepass");
+ args.push_back(password);
+ args.push_back(p_path);
+ args.push_back(user);
+ int retval;
+ int err = OS::get_singleton()->execute(jarsigner,args,true,NULL,NULL,&retval);
+ if (retval) {
+ EditorNode::add_io_error("'jarsigner' returned with error #"+itos(retval));
+ return ERR_CANT_CREATE;
+ }
+
+ ep.step("Verifying APK..",104);
+
+ args.clear();
+ args.push_back("-verify");
+ args.push_back(p_path);
+ args.push_back("-verbose");
+
+ err = OS::get_singleton()->execute(jarsigner,args,true,NULL,NULL,&retval);
+ if (retval) {
+ EditorNode::add_io_error("'jarsigner' verificaiton of APK failed. Make sure to use jarsigner from Java 6.");
+ return ERR_CANT_CREATE;
+ }
+
+ }
+ return OK;
+
+}
+
+
+bool EditorExportPlatformAndroid::poll_devices() {
+
+ bool dc=devices_changed;
+ devices_changed=false;
+ return dc;
+}
+
+int EditorExportPlatformAndroid::get_device_count() const {
+
+ device_lock->lock();
+ int dc=devices.size();
+ device_lock->unlock();
+
+ return dc;
+
+}
+String EditorExportPlatformAndroid::get_device_name(int p_device) const {
+
+ ERR_FAIL_INDEX_V(p_device,devices.size(),"");
+ device_lock->lock();
+ String s=devices[p_device].name;
+ device_lock->unlock();
+ return s;
+}
+String EditorExportPlatformAndroid::get_device_info(int p_device) const {
+
+ ERR_FAIL_INDEX_V(p_device,devices.size(),"");
+ device_lock->lock();
+ String s=devices[p_device].description;
+ device_lock->unlock();
+ return s;
+}
+
+void EditorExportPlatformAndroid::_device_poll_thread(void *ud) {
+
+ EditorExportPlatformAndroid *ea=(EditorExportPlatformAndroid *)ud;
+
+
+ while(!ea->quit_request) {
+
+ String adb=EditorSettings::get_singleton()->get("android/adb");
+ if (!FileAccess::exists(adb)) {
+ OS::get_singleton()->delay_usec(3000000);
+ continue; //adb not configured
+ }
+
+ String devices;
+ List<String> args;
+ args.push_back("devices");
+ int ec;
+ Error err = OS::get_singleton()->execute(adb,args,true,NULL,&devices,&ec);
+ Vector<String> ds = devices.split("\n");
+ Vector<String> ldevices;
+ for(int i=1;i<ds.size();i++) {
+
+ String d = ds[i];
+ int dpos = d.find("device");
+ if (dpos==-1)
+ continue;
+ d=d.substr(0,dpos).strip_edges();
+// print_line("found devuce: "+d);
+ ldevices.push_back(d);
+ }
+
+ ea->device_lock->lock();
+
+ bool different=false;
+
+ if (devices.size()!=ldevices.size()) {
+
+ different=true;
+ } else {
+
+ for(int i=0;i<ea->devices.size();i++) {
+
+ if (ea->devices[i].id!=ldevices[i]) {
+ different=true;
+ break;
+ }
+ }
+ }
+
+ if (different) {
+
+
+ Vector<Device> ndevices;
+
+ for(int i=0;i<ldevices.size();i++) {
+
+ Device d;
+ d.id=ldevices[i];
+ for(int j=0;j<ea->devices.size();j++) {
+ if (ea->devices[j].id==ldevices[i]) {
+ d.description=ea->devices[j].description;
+ d.name=ea->devices[j].name;
+ }
+ }
+
+ if (d.description=="") {
+ //in the oven, request!
+ args.clear();
+ args.push_back("-s");
+ args.push_back(d.id);
+ args.push_back("shell");
+ args.push_back("cat");
+ args.push_back("/system/build.prop");
+ int ec;
+ String dp;
+
+ Error err = OS::get_singleton()->execute(adb,args,true,NULL,&dp,&ec);
+ print_line("RV: "+itos(ec));
+ Vector<String> props = dp.split("\n");
+ String vendor;
+ String device;
+ d.description+"Device ID: "+d.id+"\n";
+ for(int j=0;j<props.size();j++) {
+
+ String p = props[j];
+ if (p.begins_with("ro.product.model=")) {
+ device=p.get_slice("=",1).strip_edges();
+ } else if (p.begins_with("ro.product.brand=")) {
+ vendor=p.get_slice("=",1).strip_edges().capitalize();
+ } else if (p.begins_with("ro.build.display.id=")) {
+ d.description+="Build: "+p.get_slice("=",1).strip_edges()+"\n";
+ } else if (p.begins_with("ro.build.version.release=")) {
+ d.description+="Release: "+p.get_slice("=",1).strip_edges()+"\n";
+ } else if (p.begins_with("ro.product.cpu.abi=")) {
+ d.description+="CPU: "+p.get_slice("=",1).strip_edges()+"\n";
+ } else if (p.begins_with("ro.product.manufacturer=")) {
+ d.description+="Manufacturer: "+p.get_slice("=",1).strip_edges()+"\n";
+ } else if (p.begins_with("ro.board.platform=")) {
+ d.description+="Chipset: "+p.get_slice("=",1).strip_edges()+"\n";
+ } else if (p.begins_with("ro.opengles.version=")) {
+ uint32_t opengl = p.get_slice("=",1).to_int();
+ d.description+="OpenGL: "+itos(opengl>>16)+"."+itos((opengl>>8)&0xFF)+"."+itos((opengl)&0xFF)+"\n";
+ }
+ }
+
+ d.name=vendor+" "+device;
+// print_line("name: "+d.name);
+// print_line("description: "+d.description);
+
+ }
+
+ ndevices.push_back(d);
+
+ }
+
+ ea->devices=ndevices;
+ ea->devices_changed=true;
+ }
+
+ ea->device_lock->unlock();
+
+ OS::get_singleton()->delay_usec(3000000);
+ }
+
+}
+
+Error EditorExportPlatformAndroid::run(int p_device) {
+
+ ERR_FAIL_INDEX_V(p_device,devices.size(),ERR_INVALID_PARAMETER);
+ device_lock->lock();
+
+ EditorProgress ep("run","Running on "+devices[p_device].name,3);
+
+ String adb=EditorSettings::get_singleton()->get("android/adb");
+ if (adb=="") {
+
+ EditorNode::add_io_error("ADB executable not configured in settings, can't run.");
+ device_lock->unlock();
+ return ERR_UNCONFIGURED;
+ }
+
+ //export_temp
+ ep.step("Exporting APK",0);
+
+ String export_to=EditorSettings::get_singleton()->get_settings_path()+"/tmp/tmpexport.apk";
+ Error err = export_project(export_to,true);
+ if (err) {
+ device_lock->unlock();
+ return err;
+ }
+
+ ep.step("Uninstalling..",1);
+
+ print_line("Uninstalling previous version: "+devices[p_device].name);
+ List<String> args;
+ args.push_back("-s");
+ args.push_back(devices[p_device].id);
+ args.push_back("uninstall");
+ args.push_back(package);
+ int rv;
+ err = OS::get_singleton()->execute(adb,args,true,NULL,NULL,&rv);
+#if 0
+ if (err || rv!=0) {
+ EditorNode::add_io_error("Could not install to device.");
+ device_lock->unlock();
+ return ERR_CANT_CREATE;
+ }
+#endif
+ print_line("Installing into device (please wait..): "+devices[p_device].name);
+ ep.step("Installing to Device (please wait..)..",2);
+
+ args.clear();
+ args.push_back("-s");
+ args.push_back(devices[p_device].id);
+ args.push_back("install");
+ args.push_back(export_to);
+ rv;
+ err = OS::get_singleton()->execute(adb,args,true,NULL,NULL,&rv);
+ if (err || rv!=0) {
+ EditorNode::add_io_error("Could not install to device.");
+ device_lock->unlock();
+ return ERR_CANT_CREATE;
+ }
+
+ ep.step("Running on Device..",3);
+ args.clear();
+ args.push_back("-s");
+ args.push_back(devices[p_device].id);
+ args.push_back("shell");
+ args.push_back("am");
+ args.push_back("start");
+ args.push_back("-a");
+ args.push_back("android.intent.action.MAIN");
+ args.push_back("-n");
+ args.push_back(package+"/com.android.godot.Godot");
+
+ err = OS::get_singleton()->execute(adb,args,true,NULL,NULL,&rv);
+ if (err || rv!=0) {
+ EditorNode::add_io_error("Could not execute ondevice.");
+ device_lock->unlock();
+ return ERR_CANT_CREATE;
+ }
+ device_lock->unlock();
+ return OK;
+}
+
+
+EditorExportPlatformAndroid::EditorExportPlatformAndroid() {
+
+ version_code=1;
+ version_name="1.0";
+ package="com.android.noname";
+ name="";
+ _signed=true;
+ device_lock = Mutex::create();
+ quit_request=false;
+ orientation=0;
+
+ device_thread=Thread::create(_device_poll_thread,this);
+ devices_changed=true;
+
+ Image img( _android_logo );
+ logo = Ref<ImageTexture>( memnew( ImageTexture ));
+ logo->create_from_image(img);
+}
+
+bool EditorExportPlatformAndroid::can_export(String *r_error) const {
+
+ bool valid=true;
+ String adb=EditorSettings::get_singleton()->get("android/adb");
+ String err;
+
+ if (!FileAccess::exists(adb)) {
+
+ valid=false;
+ err+="ADB executable not configured in editor settings.\n";
+ }
+
+ String js = EditorSettings::get_singleton()->get("android/jarsigner");
+
+ if (!FileAccess::exists(js)) {
+
+ valid=false;
+ err+="OpenJDK 6 jarsigner not configured in editor settings.\n";
+ }
+
+ String dk = EditorSettings::get_singleton()->get("android/debug_keystore");
+
+ if (!FileAccess::exists(dk)) {
+
+ valid=false;
+ err+="Debug Keystore not configured in editor settings.\n";
+ }
+
+
+ String exe_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/";
+
+ if (!FileAccess::exists(exe_path+"android_debug.apk") || !FileAccess::exists(exe_path+"android_release.apk")) {
+ valid=false;
+ err+="No export templates found.\nDownload and install export templates.\n";
+ }
+
+ if (custom_debug_package!="" && !FileAccess::exists(custom_debug_package)) {
+ valid=false;
+ err+="Custom debug package not found.\n";
+ }
+
+ if (custom_release_package!="" && !FileAccess::exists(custom_release_package)) {
+ valid=false;
+ err+="Custom release package not found.\n";
+ }
+
+ if (r_error)
+ *r_error=err;
+
+ return valid;
+}
+
+
+EditorExportPlatformAndroid::~EditorExportPlatformAndroid() {
+
+ quit_request=true;
+ Thread::wait_to_finish(device_thread);
+}
+
+
+void register_android_exporter() {
+
+ String exe_ext=OS::get_singleton()->get_name()=="Windows"?"exe":"";
+ EDITOR_DEF("android/adb","");
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,"android/adb",PROPERTY_HINT_GLOBAL_FILE,exe_ext));
+ EDITOR_DEF("android/jarsigner","");
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,"android/jarsigner",PROPERTY_HINT_GLOBAL_FILE,exe_ext));
+ EDITOR_DEF("android/debug_keystore","");
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,"android/debug_keystore",PROPERTY_HINT_GLOBAL_FILE,"keystore"));
+ EDITOR_DEF("android/debug_keystore_user","androiddebugkey");
+ EDITOR_DEF("android/debug_keystore_pass","android");
+ //EDITOR_DEF("android/release_keystore","");
+ //EDITOR_DEF("android/release_username","");
+ //EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,"android/release_keystore",PROPERTY_HINT_GLOBAL_FILE,"*.keystore"));
+
+ Ref<EditorExportPlatformAndroid> exporter = Ref<EditorExportPlatformAndroid>( memnew(EditorExportPlatformAndroid) );
+ EditorImportExport::get_singleton()->add_export_platform(exporter);
+
+
+}
+
diff --git a/platform/android/export/export.h b/platform/android/export/export.h
new file mode 100644
index 0000000000..88581802b8
--- /dev/null
+++ b/platform/android/export/export.h
@@ -0,0 +1,3 @@
+
+
+void register_android_exporter();
diff --git a/platform/android/file_access_android.cpp b/platform/android/file_access_android.cpp
new file mode 100644
index 0000000000..f1a2bf5882
--- /dev/null
+++ b/platform/android/file_access_android.cpp
@@ -0,0 +1,187 @@
+/*************************************************************************/
+/* file_access_android.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "file_access_android.h"
+#include "print_string.h"
+
+#ifdef ANDROID_NATIVE_ACTIVITY
+
+
+AAssetManager *FileAccessAndroid::asset_manager=NULL;
+
+
+void FileAccessAndroid::make_default() {
+
+ create_func=create_android;
+}
+
+FileAccess* FileAccessAndroid::create_android() {
+
+ return memnew(FileAccessAndroid);
+}
+
+
+Error FileAccessAndroid::open(const String& p_path, int p_mode_flags) {
+
+ String path=fix_path(p_path).simplify_path();
+ if (path.begins_with("/"))
+ path=path.substr(1,path.length());
+ else if (path.begins_with("res://"))
+ path=path.substr(6,path.length());
+
+
+
+ ERR_FAIL_COND_V(p_mode_flags&FileAccess::WRITE,ERR_UNAVAILABLE); //can't write on android..
+ a=AAssetManager_open(asset_manager,path.utf8().get_data(),AASSET_MODE_STREAMING);
+ if (!a)
+ return ERR_CANT_OPEN;
+ //ERR_FAIL_COND_V(!a,ERR_FILE_NOT_FOUND);
+ len=AAsset_getLength(a);
+ pos=0;
+ eof=false;
+
+ return OK;
+}
+
+void FileAccessAndroid::close() {
+
+ if (!a)
+ return;
+ AAsset_close(a);
+ a=NULL;
+}
+bool FileAccessAndroid::is_open() const {
+
+ return a!=NULL;
+}
+
+void FileAccessAndroid::seek(size_t p_position) {
+
+ ERR_FAIL_COND(!a);
+ AAsset_seek(a,p_position,SEEK_SET);
+ pos=p_position;
+ if (pos>len) {
+ pos=len;
+ eof=true;
+ } else {
+ eof=false;
+ }
+
+}
+void FileAccessAndroid::seek_end(int64_t p_position) {
+
+ ERR_FAIL_COND(!a);
+ AAsset_seek(a,p_position,SEEK_END);
+ pos=len+p_position;
+
+}
+size_t FileAccessAndroid::get_pos() const {
+
+ return pos;
+}
+size_t FileAccessAndroid::get_len() const {
+
+ return len;
+}
+
+bool FileAccessAndroid::eof_reached() const {
+
+ return eof;
+}
+
+uint8_t FileAccessAndroid::get_8() const {
+
+
+ if (pos>=len) {
+ eof=true;
+ return 0;
+ }
+
+
+ uint8_t byte;
+ AAsset_read(a,&byte,1);
+ pos++;
+ return byte;
+
+}
+int FileAccessAndroid::get_buffer(uint8_t *p_dst, int p_length) const {
+
+
+ off_t r = AAsset_read(a,p_dst,p_length);
+ if (r>=0) {
+ pos+=r;
+ if (pos>len) {
+ pos=len;
+ eof=true;
+ }
+ }
+ return r;
+
+}
+
+Error FileAccessAndroid::get_error() const {
+
+ return eof?ERR_FILE_EOF:OK; //not sure what else it may happen
+}
+
+void FileAccessAndroid::store_8(uint8_t p_dest) {
+
+ ERR_FAIL();
+
+}
+
+bool FileAccessAndroid::file_exists(const String& p_path) {
+
+ String path=fix_path(p_path).simplify_path();
+ if (path.begins_with("/"))
+ path=path.substr(1,path.length());
+ else if (path.begins_with("res://"))
+ path=path.substr(6,path.length());
+
+ AAsset *at=AAssetManager_open(asset_manager,path.utf8().get_data(),AASSET_MODE_STREAMING);
+
+ if (!at)
+ return false;
+
+ AAsset_close(at);
+ return true;
+
+}
+
+
+FileAccessAndroid::FileAccessAndroid() {
+ a=NULL;
+ eof=false;
+}
+
+
+FileAccessAndroid::~FileAccessAndroid()
+{
+ close();
+}
+#endif
diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h
new file mode 100644
index 0000000000..080ab1a6ce
--- /dev/null
+++ b/platform/android/file_access_android.h
@@ -0,0 +1,82 @@
+/*************************************************************************/
+/* file_access_android.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef FILE_ACCESS_ANDROID_H
+#define FILE_ACCESS_ANDROID_H
+
+#ifdef ANDROID_NATIVE_ACTIVITY
+
+
+#include "os/file_access.h"
+#include <stdio.h>
+#include <android/asset_manager.h>
+#include <android/log.h>
+#include <android_native_app_glue.h>
+
+
+class FileAccessAndroid : public FileAccess {
+
+ static FileAccess* create_android();
+ mutable AAsset *a;
+ mutable size_t len;
+ mutable size_t pos;
+ mutable bool eof;
+
+public:
+
+ static AAssetManager *asset_manager;
+
+ virtual Error open(const String& p_path, int p_mode_flags); ///< open a file
+ virtual void close(); ///< close a file
+ virtual bool is_open() const; ///< true when file is open
+
+ virtual void seek(size_t p_position); ///< seek to a given position
+ virtual void seek_end(int64_t p_position=0); ///< seek from the end of file
+ virtual size_t get_pos() const; ///< get position in the file
+ virtual size_t get_len() const; ///< get size of the file
+
+ virtual bool eof_reached() const; ///< reading passed EOF
+
+ virtual uint8_t get_8() const; ///< get a byte
+ virtual int get_buffer(uint8_t *p_dst, int p_length) const;
+
+ virtual Error get_error() const; ///< get last error
+
+ virtual void store_8(uint8_t p_dest); ///< store a byte
+
+ virtual bool file_exists(const String& p_path); ///< return true if a file exists
+
+
+ static void make_default();
+
+ FileAccessAndroid();
+ ~FileAccessAndroid();
+};
+
+#endif // FILE_ACCESS_ANDROID_H
+#endif
diff --git a/platform/android/file_access_jandroid.cpp b/platform/android/file_access_jandroid.cpp
new file mode 100644
index 0000000000..e1dec4f601
--- /dev/null
+++ b/platform/android/file_access_jandroid.cpp
@@ -0,0 +1,253 @@
+/*************************************************************************/
+/* file_access_jandroid.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef ANDROID_NATIVE_ACTIVITY
+
+#include "file_access_jandroid.h"
+#include "os/os.h"
+#include <unistd.h>
+#include "thread_jandroid.h"
+
+jobject FileAccessJAndroid::io=NULL;
+jclass FileAccessJAndroid::cls;
+jmethodID FileAccessJAndroid::_file_open=0;
+jmethodID FileAccessJAndroid::_file_get_size=0;
+jmethodID FileAccessJAndroid::_file_seek=0;
+jmethodID FileAccessJAndroid::_file_read=0;
+jmethodID FileAccessJAndroid::_file_tell=0;
+jmethodID FileAccessJAndroid::_file_eof=0;
+jmethodID FileAccessJAndroid::_file_close=0;
+
+
+FileAccess* FileAccessJAndroid::create_jandroid() {
+
+ return memnew(FileAccessJAndroid);
+}
+
+Error FileAccessJAndroid::_open(const String& p_path, int p_mode_flags) {
+
+ if (is_open())
+ close();
+
+ String path=fix_path(p_path).simplify_path();
+ if (path.begins_with("/"))
+ path=path.substr(1,path.length());
+ else if (path.begins_with("res://"))
+ path=path.substr(6,path.length());
+
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ //OS::get_singleton()->print("env: %p, io %p, fo: %p\n",env,io,_file_open);
+
+
+ jstring js = env->NewStringUTF(path.utf8().get_data());
+ int res = env->CallIntMethod(io,_file_open,js,p_mode_flags&WRITE?true:false);
+
+ env->DeleteLocalRef(js);
+
+ if (res<=0)
+ return ERR_FILE_CANT_OPEN;
+ id=res;
+
+
+ return OK;
+}
+
+void FileAccessJAndroid::close() {
+
+ if (!is_open())
+ return;
+
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ env->CallVoidMethod(io,_file_close,id);
+ id=0;
+
+}
+bool FileAccessJAndroid::is_open() const {
+
+ return id!=0;
+}
+
+void FileAccessJAndroid::seek(size_t p_position) {
+
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ ERR_FAIL_COND(!is_open());
+ env->CallVoidMethod(io,_file_seek,id,p_position);
+}
+void FileAccessJAndroid::seek_end(int64_t p_position) {
+
+ ERR_FAIL_COND(!is_open());
+
+ seek(get_len());
+
+}
+size_t FileAccessJAndroid::get_pos() const {
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ ERR_FAIL_COND_V(!is_open(),0);
+ return env->CallIntMethod(io,_file_tell,id);
+
+}
+size_t FileAccessJAndroid::get_len() const {
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ ERR_FAIL_COND_V(!is_open(),0);
+ return env->CallIntMethod(io,_file_get_size,id);
+
+
+}
+
+bool FileAccessJAndroid::eof_reached() const {
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ ERR_FAIL_COND_V(!is_open(),0);
+ return env->CallIntMethod(io,_file_eof,id);
+
+}
+
+uint8_t FileAccessJAndroid::get_8() const {
+
+ ERR_FAIL_COND_V(!is_open(),0);
+ uint8_t byte;
+ get_buffer(&byte,1);
+ return byte;
+}
+int FileAccessJAndroid::get_buffer(uint8_t *p_dst, int p_length) const {
+
+ ERR_FAIL_COND_V(!is_open(),0);
+ if (p_length==0)
+ return 0;
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ jbyteArray jca = (jbyteArray)env->CallObjectMethod(io,_file_read,id,p_length);
+
+
+ int len = env->GetArrayLength(jca);
+ env->GetByteArrayRegion(jca,0,len,(jbyte*)p_dst);
+ env->DeleteLocalRef((jobject)jca);
+
+ return len;
+
+}
+
+Error FileAccessJAndroid::get_error() const {
+
+ if (eof_reached())
+ return ERR_FILE_EOF;
+ return OK;
+}
+
+void FileAccessJAndroid::store_8(uint8_t p_dest) {
+
+
+}
+
+bool FileAccessJAndroid::file_exists(const String& p_path) {
+
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ String path=fix_path(p_path).simplify_path();
+ if (path.begins_with("/"))
+ path=path.substr(1,path.length());
+ else if (path.begins_with("res://"))
+ path=path.substr(6,path.length());
+
+ jstring js = env->NewStringUTF(path.utf8().get_data());
+ int res = env->CallIntMethod(io,_file_open,js,false);
+ if (res<=0)
+ return false;
+ env->CallVoidMethod(io,_file_close,res);
+ env->DeleteLocalRef(js);
+ return true;
+
+}
+
+
+void FileAccessJAndroid::setup( jobject p_io) {
+
+
+ io=p_io;
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP5");
+
+ jclass c = env->GetObjectClass(io);
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP6");
+ cls=(jclass)env->NewGlobalRef(c);
+
+ _file_open = env->GetMethodID(cls, "file_open", "(Ljava/lang/String;Z)I");
+ if(_file_open != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_open ok!!");
+ }
+ _file_get_size = env->GetMethodID(cls, "file_get_size", "(I)I");
+ if(_file_get_size != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_get_size ok!!");
+ }
+ _file_tell = env->GetMethodID(cls, "file_tell", "(I)I");
+ if(_file_tell != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_tell ok!!");
+ }
+ _file_eof = env->GetMethodID(cls, "file_eof", "(I)Z");
+
+ if(_file_eof != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_eof ok!!");
+ }
+ _file_seek = env->GetMethodID(cls, "file_seek", "(II)V");
+ if(_file_seek != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_seek ok!!");
+ }
+ _file_read = env->GetMethodID(cls, "file_read", "(II)[B");
+ if(_file_read != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_read ok!!");
+ }
+ _file_close = env->GetMethodID(cls, "file_close", "(I)V");
+ if(_file_close != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_close ok!!");
+ }
+
+// (*env)->CallVoidMethod(env,obj,aMethodID, myvar);
+}
+
+
+FileAccessJAndroid::FileAccessJAndroid()
+{
+
+ id=0;
+}
+
+FileAccessJAndroid::~FileAccessJAndroid()
+{
+
+ if (is_open())
+ close();
+}
+
+
+#endif
diff --git a/platform/android/file_access_jandroid.h b/platform/android/file_access_jandroid.h
new file mode 100644
index 0000000000..3cbeab5ffc
--- /dev/null
+++ b/platform/android/file_access_jandroid.h
@@ -0,0 +1,87 @@
+/*************************************************************************/
+/* file_access_jandroid.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef FILE_ACCESS_JANDROID_H
+#define FILE_ACCESS_JANDROID_H
+
+#ifndef ANDROID_NATIVE_ACTIVITY
+
+#include "java_glue.h"
+#include "os/file_access.h"
+class FileAccessJAndroid : public FileAccess {
+
+ static jobject io;
+ static jclass cls;
+
+ static jmethodID _file_open;
+ static jmethodID _file_get_size;
+ static jmethodID _file_seek;
+ static jmethodID _file_tell;
+ static jmethodID _file_eof;
+ static jmethodID _file_read;
+ static jmethodID _file_close;
+
+ int id;
+ static FileAccess* create_jandroid();
+
+
+public:
+
+ virtual Error _open(const String& p_path, int p_mode_flags); ///< open a file
+ virtual void close(); ///< close a file
+ virtual bool is_open() const; ///< true when file is open
+
+ virtual void seek(size_t p_position); ///< seek to a given position
+ virtual void seek_end(int64_t p_position=0); ///< seek from the end of file
+ virtual size_t get_pos() const; ///< get position in the file
+ virtual size_t get_len() const; ///< get size of the file
+
+ virtual bool eof_reached() const; ///< reading passed EOF
+
+ virtual uint8_t get_8() const; ///< get a byte
+ virtual int get_buffer(uint8_t *p_dst, int p_length) const;
+
+ virtual Error get_error() const; ///< get last error
+
+ virtual void store_8(uint8_t p_dest); ///< store a byte
+
+ virtual bool file_exists(const String& p_path); ///< return true if a file exists
+
+
+
+ static void setup( jobject io);
+
+ virtual uint64_t _get_modified_time(const String& p_file) { return 0; }
+
+ FileAccessJAndroid();
+ ~FileAccessJAndroid();
+};
+
+#endif
+
+#endif // FILE_ACCESS_JANDROID_H
diff --git a/platform/android/globals/global_defaults.cpp b/platform/android/globals/global_defaults.cpp
new file mode 100644
index 0000000000..c6f852a592
--- /dev/null
+++ b/platform/android/globals/global_defaults.cpp
@@ -0,0 +1,13 @@
+
+#include "global_defaults.h"
+#include "globals.h"
+
+
+void register_android_global_defaults() {
+
+ GLOBAL_DEF("rasterizer.Android/use_fragment_lighting",false);
+ GLOBAL_DEF("display.Android/driver","GLES2");
+ GLOBAL_DEF("rasterizer.Android/trilinear_mipmap_filter",false);
+
+ Globals::get_singleton()->set_custom_property_info("display.Android/driver",PropertyInfo(Variant::STRING,"display.Android/driver",PROPERTY_HINT_ENUM,"GLES1,GLES2"));
+}
diff --git a/platform/android/globals/global_defaults.h b/platform/android/globals/global_defaults.h
new file mode 100644
index 0000000000..64eb26c482
--- /dev/null
+++ b/platform/android/globals/global_defaults.h
@@ -0,0 +1,3 @@
+
+
+void register_android_global_defaults(); \ No newline at end of file
diff --git a/platform/android/godot_android.cpp b/platform/android/godot_android.cpp
new file mode 100644
index 0000000000..673ff91641
--- /dev/null
+++ b/platform/android/godot_android.cpp
@@ -0,0 +1,993 @@
+/*************************************************************************/
+/* godot_android.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifdef ANDROID_NATIVE_ACTIVITY
+
+#include <jni.h>
+#include <errno.h>
+
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+
+#include <android/sensor.h>
+#include <android/window.h>
+#include <android/log.h>
+#include <android_native_app_glue.h>
+#include "file_access_android.h"
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "os_android.h"
+#include "globals.h"
+#include "main/main.h"
+#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "godot", __VA_ARGS__))
+#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "godot", __VA_ARGS__))
+
+
+extern "C" {
+ JNIEXPORT void JNICALL Java_com_android_godot_Godot_registerSingleton(JNIEnv * env, jobject obj, jstring name,jobject p_object);
+ JNIEXPORT void JNICALL Java_com_android_godot_Godot_registerMethod(JNIEnv * env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args);
+ JNIEXPORT jstring JNICALL Java_com_android_godot_Godot_getGlobal(JNIEnv * env, jobject obj, jstring path);
+};
+
+class JNISingleton : public Object {
+
+ OBJ_TYPE( JNISingleton, Object );
+
+
+ struct MethodData {
+
+
+ jmethodID method;
+ Variant::Type ret_type;
+ Vector<Variant::Type> argtypes;
+ };
+
+ jobject instance;
+ Map<StringName,MethodData> method_map;
+ JNIEnv *env;
+
+public:
+
+ void update_env(JNIEnv *p_env) { env=p_env; }
+
+ virtual Variant call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error) {
+
+ print_line("attempt to call "+String(p_method));
+
+ r_error.error=Variant::CallError::CALL_OK;
+
+ Map<StringName,MethodData >::Element *E=method_map.find(p_method);
+ if (!E) {
+
+ print_line("no exists");
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ return Variant();
+ }
+
+
+ int ac = E->get().argtypes.size();
+ if (ac<p_argcount) {
+
+ print_line("fewargs");
+ r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument=ac;
+ return Variant();
+ }
+
+ if (ac>p_argcount) {
+
+ print_line("manyargs");
+ r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument=ac;
+ return Variant();
+ }
+
+
+
+ for(int i=0;i<p_argcount;i++) {
+
+ if (!Variant::can_convert(p_args[i]->get_type(),E->get().argtypes[i])) {
+
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=i;
+ r_error.expected=E->get().argtypes[i];
+ }
+ }
+
+
+ jvalue *v=NULL;
+
+ if (p_argcount) {
+
+ v=(jvalue*)alloca( sizeof(jvalue)*p_argcount );
+ }
+
+ for(int i=0;i<p_argcount;i++) {
+
+
+ switch(E->get().argtypes[i]) {
+
+ case Variant::BOOL: {
+
+ v[i].z=*p_args[i];
+ } break;
+ case Variant::INT: {
+
+ v[i].i=*p_args[i];
+ } break;
+ case Variant::REAL: {
+
+ v[i].f=*p_args[i];
+ } break;
+ case Variant::STRING: {
+
+ String s = *p_args[i];
+ jstring jStr = env->NewStringUTF(s.utf8().get_data());
+ v[i].l=jStr;
+ } break;
+ case Variant::STRING_ARRAY: {
+
+ DVector<String> sarray = *p_args[i];
+ jobjectArray arr = env->NewObjectArray(sarray.size(),env->FindClass("java/lang/String"),env->NewStringUTF(""));
+
+ for(int j=0;j<sarray.size();j++) {
+
+ env->SetObjectArrayElement(arr,j,env->NewStringUTF( sarray[i].utf8().get_data() ));
+ }
+ v[i].l=arr;
+
+ } break;
+ case Variant::INT_ARRAY: {
+
+ DVector<int> array = *p_args[i];
+ jintArray arr = env->NewIntArray(array.size());
+ DVector<int>::Read r = array.read();
+ env->SetIntArrayRegion(arr,0,array.size(),r.ptr());
+ v[i].l=arr;
+
+ } break;
+ case Variant::REAL_ARRAY: {
+
+ DVector<float> array = *p_args[i];
+ jfloatArray arr = env->NewFloatArray(array.size());
+ DVector<float>::Read r = array.read();
+ env->SetFloatArrayRegion(arr,0,array.size(),r.ptr());
+ v[i].l=arr;
+
+ } break;
+ default: {
+
+ ERR_FAIL_V(Variant());
+ } break;
+
+ }
+ }
+
+ print_line("calling method!!");
+
+ Variant ret;
+
+ switch(E->get().ret_type) {
+
+ case Variant::NIL: {
+
+
+ print_line("call void");
+ env->CallVoidMethodA(instance,E->get().method,v);
+ } break;
+ case Variant::BOOL: {
+
+ ret = env->CallBooleanMethodA(instance,E->get().method,v);
+ print_line("call bool");
+ } break;
+ case Variant::INT: {
+
+ ret = env->CallIntMethodA(instance,E->get().method,v);
+ print_line("call int");
+ } break;
+ case Variant::REAL: {
+
+ ret = env->CallFloatMethodA(instance,E->get().method,v);
+ } break;
+ case Variant::STRING: {
+
+ jobject o = env->CallObjectMethodA(instance,E->get().method,v);
+ String singname = env->GetStringUTFChars((jstring)o, NULL );
+ } break;
+ case Variant::STRING_ARRAY: {
+
+ jobjectArray arr = (jobjectArray)env->CallObjectMethodA(instance,E->get().method,v);
+
+ int stringCount = env->GetArrayLength(arr);
+ DVector<String> sarr;
+
+ for (int i=0; i<stringCount; i++) {
+ jstring string = (jstring) env->GetObjectArrayElement(arr, i);
+ const char *rawString = env->GetStringUTFChars(string, 0);
+ sarr.push_back(String(rawString));
+ }
+
+ ret=sarr;
+
+ } break;
+ case Variant::INT_ARRAY: {
+
+ jintArray arr = (jintArray)env->CallObjectMethodA(instance,E->get().method,v);
+
+ int fCount = env->GetArrayLength(arr);
+ DVector<int> sarr;
+ sarr.resize(fCount);
+
+ DVector<int>::Write w = sarr.write();
+ env->GetIntArrayRegion(arr,0,fCount,w.ptr());
+ w = DVector<int>::Write();
+ ret=sarr;
+ } break;
+ case Variant::REAL_ARRAY: {
+
+ jfloatArray arr = (jfloatArray)env->CallObjectMethodA(instance,E->get().method,v);
+
+ int fCount = env->GetArrayLength(arr);
+ DVector<float> sarr;
+ sarr.resize(fCount);
+
+ DVector<float>::Write w = sarr.write();
+ env->GetFloatArrayRegion(arr,0,fCount,w.ptr());
+ w = DVector<float>::Write();
+ ret=sarr;
+ } break;
+ default: {
+
+
+ print_line("failure..");
+ ERR_FAIL_V(Variant());
+ } break;
+ }
+
+ print_line("success");
+
+ return ret;
+ }
+
+
+ jobject get_instance() const {
+
+ return instance;
+ }
+ void set_instance(jobject p_instance) {
+
+ instance=p_instance;
+ }
+
+
+ void add_method(const StringName& p_name, jmethodID p_method,const Vector<Variant::Type>& p_args, Variant::Type p_ret_type) {
+
+ MethodData md;
+ md.method=p_method;
+ md.argtypes=p_args;
+ md.ret_type=p_ret_type;
+ method_map[p_name]=md;
+
+ }
+
+
+ JNISingleton() {}
+
+};
+
+//JNIEnv *JNISingleton::env=NULL;
+
+static HashMap<String,JNISingleton*> jni_singletons;
+
+
+struct engine {
+ struct android_app* app;
+ OS_Android *os;
+ JNIEnv *jni;
+
+ ASensorManager* sensorManager;
+ const ASensor* accelerometerSensor;
+ ASensorEventQueue* sensorEventQueue;
+
+ bool display_active;
+ bool requested_quit;
+ int animating;
+ EGLDisplay display;
+ EGLSurface surface;
+ EGLContext context;
+ int32_t width;
+ int32_t height;
+
+};
+
+/**
+ * Initialize an EGL context for the current display.
+ */
+static int engine_init_display(struct engine* engine,bool p_gl2) {
+ // initialize OpenGL ES and EGL
+
+ /*
+ * Here specify the attributes of the desired configuration.
+ * Below, we select an EGLConfig with at least 8 bits per color
+ * component compatible with on-screen windows
+ */
+ const EGLint gl2_attribs[] = {
+ // EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_BLUE_SIZE, 4,
+ EGL_GREEN_SIZE, 4,
+ EGL_RED_SIZE, 4,
+ EGL_ALPHA_SIZE, 0,
+ EGL_DEPTH_SIZE, 16,
+ EGL_STENCIL_SIZE, EGL_DONT_CARE,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_NONE
+ };
+
+ const EGLint gl1_attribs[] = {
+ // EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_BLUE_SIZE, 4,
+ EGL_GREEN_SIZE, 4,
+ EGL_RED_SIZE, 4,
+ EGL_ALPHA_SIZE, 0,
+ EGL_DEPTH_SIZE, 16,
+ EGL_STENCIL_SIZE, EGL_DONT_CARE,
+ EGL_NONE
+ };
+
+ const EGLint *attribs=p_gl2?gl2_attribs:gl1_attribs;
+
+
+ EGLint w, h, dummy, format;
+ EGLint numConfigs;
+ EGLConfig config;
+ EGLSurface surface;
+ EGLContext context;
+
+ EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+
+ eglInitialize(display, 0, 0);
+
+
+ /* Here, the application chooses the configuration it desires. In this
+ * sample, we have a very simplified selection process, where we pick
+ * the first EGLConfig that matches our criteria */
+
+ eglChooseConfig(display, attribs, &config, 1, &numConfigs);
+
+ LOGI("Num configs: %i\n",numConfigs);
+
+ /* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
+ * guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
+ * As soon as we picked a EGLConfig, we can safely reconfigure the
+ * ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */
+ eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
+
+ ANativeWindow_setBuffersGeometry(engine->app->window, 0, 0, format);
+ //ANativeWindow_setFlags(engine->app->window, 0, 0, format|);
+
+ surface = eglCreateWindowSurface(display, config, engine->app->window, NULL);
+
+ const EGLint context_attribs[] = {
+ EGL_CONTEXT_CLIENT_VERSION,2,
+ EGL_NONE
+ };
+ context = eglCreateContext(display, config, EGL_NO_CONTEXT, p_gl2?context_attribs:NULL);
+
+ if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
+ LOGW("Unable to eglMakeCurrent");
+ return -1;
+ }
+
+ eglQuerySurface(display, surface, EGL_WIDTH, &w);
+ eglQuerySurface(display, surface, EGL_HEIGHT, &h);
+ print_line("INIT VIDEO MODE: "+itos(w)+","+itos(h));
+
+ //engine->os->set_egl_extensions(eglQueryString(display,EGL_EXTENSIONS));
+ engine->os->init_video_mode(w,h);
+
+
+ engine->display = display;
+ engine->context = context;
+ engine->surface = surface;
+ engine->width = w;
+ engine->height = h;
+ engine->display_active=true;
+
+ //engine->state.angle = 0;
+
+ // Initialize GL state.
+ //glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
+ glEnable(GL_CULL_FACE);
+ // glShadeModel(GL_SMOOTH);
+ glDisable(GL_DEPTH_TEST);
+ LOGI("GL Version: %s - %s %s\n", glGetString(GL_VERSION),glGetString(GL_VENDOR), glGetString(GL_RENDERER));
+
+ return 0;
+}
+
+
+static void engine_draw_frame(struct engine* engine) {
+ if (engine->display == NULL) {
+ // No display.
+ return;
+ }
+
+ // Just fill the screen with a color.
+ //glClearColor(0,1,0,1);
+ //glClear(GL_COLOR_BUFFER_BIT);
+ if (engine->os && engine->os->main_loop_iterate()==true) {
+
+ engine->requested_quit=true;
+ return; //should exit instead
+ }
+
+ eglSwapBuffers(engine->display, engine->surface);
+}
+
+
+static void engine_term_display(struct engine* engine) {
+ if (engine->display != EGL_NO_DISPLAY) {
+ eglMakeCurrent(engine->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ if (engine->context != EGL_NO_CONTEXT) {
+ eglDestroyContext(engine->display, engine->context);
+ }
+ if (engine->surface != EGL_NO_SURFACE) {
+ eglDestroySurface(engine->display, engine->surface);
+ }
+ eglTerminate(engine->display);
+ }
+
+ engine->animating = 0;
+ engine->display = EGL_NO_DISPLAY;
+ engine->context = EGL_NO_CONTEXT;
+ engine->surface = EGL_NO_SURFACE;
+ engine->display_active=false;
+
+}
+
+/**
+ * Process the next input event.
+ */
+static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) {
+ struct engine* engine = (struct engine*)app->userData;
+
+ if (!engine->os)
+ return 0;
+
+ switch(AInputEvent_getType(event)) {
+
+ case AINPUT_EVENT_TYPE_KEY: {
+
+ int ac = AKeyEvent_getAction(event);
+ switch(ac) {
+
+ case AKEY_EVENT_ACTION_DOWN: {
+
+ int32_t code = AKeyEvent_getKeyCode(event);
+ if (code==AKEYCODE_BACK) {
+
+ //AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled);
+ if (engine->os)
+ engine->os->main_loop_request_quit();
+ return 1;
+
+ }
+
+
+ } break;
+ case AKEY_EVENT_ACTION_UP: {
+
+
+ } break;
+ }
+
+
+ } break;
+ case AINPUT_EVENT_TYPE_MOTION: {
+
+
+ Vector<OS_Android::TouchPos> touchvec;
+
+ int pc = AMotionEvent_getPointerCount(event);
+
+ touchvec.resize(pc);
+
+ for(int i=0;i<pc;i++) {
+
+ touchvec[i].pos.x=AMotionEvent_getX(event,i);
+ touchvec[i].pos.y=AMotionEvent_getY(event,i);
+ touchvec[i].id=AMotionEvent_getPointerId(event,i);
+ }
+
+
+ //System.out.printf("gaction: %d\n",event.getAction());
+ int pidx=(AMotionEvent_getAction(event)&AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)>>8;
+ switch(AMotionEvent_getAction(event)&AMOTION_EVENT_ACTION_MASK) {
+
+ case AMOTION_EVENT_ACTION_DOWN: {
+ engine->os->process_touch(0,0,touchvec);
+
+ //System.out.printf("action down at: %f,%f\n", event.getX(),event.getY());
+ } break;
+ case AMOTION_EVENT_ACTION_MOVE: {
+ engine->os->process_touch(1,0,touchvec);
+ //for(int i=0;i<event.getPointerCount();i++) {
+ // System.out.printf("%d - moved to: %f,%f\n",i, event.getX(i),event.getY(i));
+ //}
+ } break;
+ case AMOTION_EVENT_ACTION_POINTER_UP: {
+
+ engine->os->process_touch(4,pidx,touchvec);
+ //System.out.printf("%d - s.up at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
+ } break;
+ case AMOTION_EVENT_ACTION_POINTER_DOWN: {
+ engine->os->process_touch(3,pidx,touchvec);
+ //System.out.printf("%d - s.down at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
+ } break;
+ case AMOTION_EVENT_ACTION_CANCEL:
+ case AMOTION_EVENT_ACTION_UP: {
+ engine->os->process_touch(2,0,touchvec);
+ //for(int i=0;i<event.getPointerCount();i++) {
+ // System.out.printf("%d - up! %f,%f\n",i, event.getX(i),event.getY(i));
+ //}
+ } break;
+ }
+
+ return 1;
+ } break;
+
+ }
+
+ return 0;
+}
+
+/**
+ * Process the next main command.
+ */
+
+static void _gfx_init(void *ud,bool p_gl2) {
+
+ struct engine* engine = (struct engine*)ud;
+ engine_init_display(engine,p_gl2);
+}
+
+static void engine_handle_cmd(struct android_app* app, int32_t cmd) {
+ struct engine* engine = (struct engine*)app->userData;
+ // LOGI("**** CMD %i\n",cmd);
+ switch (cmd) {
+ case APP_CMD_SAVE_STATE:
+ // The system has asked us to save our current state. Do so.
+ //engine->app->savedState = malloc(sizeof(struct saved_state));
+ //*((struct saved_state*)engine->app->savedState) = engine->state;
+ //engine->app->savedStateSize = sizeof(struct saved_state);
+ break;
+ case APP_CMD_CONFIG_CHANGED:
+ case APP_CMD_WINDOW_RESIZED: {
+
+#if 0
+// android blows
+ if (engine->display_active) {
+
+ EGLint w,h;
+ eglQuerySurface(engine->display, engine->surface, EGL_WIDTH, &w);
+ eglQuerySurface(engine->display, engine->surface, EGL_HEIGHT, &h);
+ engine->os->init_video_mode(w,h);
+ //print_line("RESIZED VIDEO MODE: "+itos(w)+","+itos(h));
+ engine_draw_frame(engine);
+
+ }
+#else
+
+ if (engine->display_active) {
+
+
+ EGLint w,h;
+ eglQuerySurface(engine->display, engine->surface, EGL_WIDTH, &w);
+ eglQuerySurface(engine->display, engine->surface, EGL_HEIGHT, &h);
+ // if (w==engine->os->get_video_mode().width && h==engine->os->get_video_mode().height)
+ // break;
+
+ engine_term_display(engine);
+
+
+ }
+
+
+ engine->os->reload_gfx();
+ engine_draw_frame(engine);
+ engine->animating=1;
+
+ /*
+ EGLint w,h;
+ eglQuerySurface(engine->display, engine->surface, EGL_WIDTH, &w);
+ eglQuerySurface(engine->display, engine->surface, EGL_HEIGHT, &h);
+ engine->os->init_video_mode(w,h);
+ //print_line("RESIZED VIDEO MODE: "+itos(w)+","+itos(h));
+
+ }*/
+
+#endif
+
+ } break;
+ case APP_CMD_INIT_WINDOW:
+ //The window is being shown, get it ready.
+ // LOGI("INIT WINDOW");
+ if (engine->app->window != NULL) {
+
+ if (engine->os==NULL) {
+
+ //do initialization here, when there's OpenGL! hackish but the only way
+ engine->os = new OS_Android(_gfx_init,engine);
+
+ // char *args[]={"-test","gui",NULL};
+ __android_log_print(ANDROID_LOG_INFO,"godot","pre asdasd setup...");
+#if 0
+ Error err = Main::setup("apk",2,args);
+#else
+ Error err = Main::setup("apk",0,NULL);
+
+ String modules = Globals::get_singleton()->get("android/modules");
+ Vector<String> mods = modules.split(",",false);
+ mods.push_back("GodotOS");
+ __android_log_print(ANDROID_LOG_INFO,"godot","mod count: %i",mods.size());
+
+ if (mods.size()) {
+
+ jclass activityClass = engine->jni->FindClass("android/app/NativeActivity");
+
+ jmethodID getClassLoader = engine->jni->GetMethodID(activityClass,"getClassLoader", "()Ljava/lang/ClassLoader;");
+
+ jobject cls = engine->jni->CallObjectMethod(app->activity->clazz, getClassLoader);
+
+ jclass classLoader = engine->jni->FindClass("java/lang/ClassLoader");
+
+ jmethodID findClass = engine->jni->GetMethodID(classLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
+
+
+ static JNINativeMethod methods[] = {
+ {"registerSingleton", "(Ljava/lang/String;Ljava/lang/Object;)V",(void *)&Java_com_android_godot_Godot_registerSingleton},
+ {"registerMethod", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V",(void *)&Java_com_android_godot_Godot_registerMethod},
+ {"getGlobal", "(Ljava/lang/String;)Ljava/lang/String;", (void *)&Java_com_android_godot_Godot_getGlobal},
+ };
+
+ jstring gstrClassName = engine->jni->NewStringUTF("com/android/godot/Godot");
+ jclass GodotClass = (jclass)engine->jni->CallObjectMethod(cls, findClass, gstrClassName);
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","godot ****^*^*?^*^*class data %x",GodotClass);
+
+ engine->jni->RegisterNatives(GodotClass,methods,sizeof(methods)/sizeof(methods[0]));
+
+ for (int i=0;i<mods.size();i++) {
+
+ String m = mods[i];
+ //jclass singletonClass = engine->jni->FindClass(m.utf8().get_data());
+
+ jstring strClassName = engine->jni->NewStringUTF(m.utf8().get_data());
+ jclass singletonClass = (jclass)engine->jni->CallObjectMethod(cls, findClass, strClassName);
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","****^*^*?^*^*class data %x",singletonClass);
+ jmethodID initialize = engine->jni->GetStaticMethodID(singletonClass, "initialize", "(Landroid/app/Activity;)Lcom/android/godot/Godot$SingletonBase;");
+
+
+ jobject obj = engine->jni->CallStaticObjectMethod(singletonClass,initialize,app->activity->clazz);
+ __android_log_print(ANDROID_LOG_INFO,"godot","****^*^*?^*^*class instance %x",obj);
+ jobject gob = engine->jni->NewGlobalRef(obj);
+
+
+ }
+
+ }
+
+#endif
+
+
+ if (!Main::start())
+ return; //should exit instead and print the error
+
+ engine->os->main_loop_begin();
+ } else {
+ //i guess recreate resources?
+ engine->os->reload_gfx();
+ }
+
+
+ engine->animating=1;
+ engine_draw_frame(engine);
+ }
+ break;
+ case APP_CMD_TERM_WINDOW:
+ // The window is being hidden or closed, clean it up.
+ // LOGI("TERM WINDOW");
+ engine_term_display(engine);
+ break;
+ case APP_CMD_GAINED_FOCUS:
+ // When our app gains focus, we start monitoring the accelerometer.
+ if (engine->accelerometerSensor != NULL) {
+ ASensorEventQueue_enableSensor(engine->sensorEventQueue,
+ engine->accelerometerSensor);
+ // We'd like to get 60 events per second (in us).
+ ASensorEventQueue_setEventRate(engine->sensorEventQueue,
+ engine->accelerometerSensor, (1000L/60)*1000);
+
+ }
+ engine->animating = 1;
+ break;
+ case APP_CMD_LOST_FOCUS:
+ // When our app loses focus, we stop monitoring the accelerometer.
+ // This is to avoid consuming battery while not being used.
+ if (engine->accelerometerSensor != NULL) {
+ ASensorEventQueue_disableSensor(engine->sensorEventQueue,
+ engine->accelerometerSensor);
+ }
+ // Also stop animating.
+ engine->animating = 0;
+ engine_draw_frame(engine);
+ break;
+ }
+}
+
+void android_main(struct android_app* state) {
+ struct engine engine;
+ // Make sure glue isn't stripped.
+ app_dummy();
+
+ memset(&engine, 0, sizeof(engine));
+ state->userData = &engine;
+ state->onAppCmd = engine_handle_cmd;
+ state->onInputEvent = engine_handle_input;
+ engine.app = state;
+ engine.requested_quit=false;
+ engine.os=NULL;
+ engine.display_active=false;
+
+ FileAccessAndroid::asset_manager=state->activity->assetManager;
+
+ // Prepare to monitor accelerometer
+ engine.sensorManager = ASensorManager_getInstance();
+ engine.accelerometerSensor = ASensorManager_getDefaultSensor(engine.sensorManager,
+ ASENSOR_TYPE_ACCELEROMETER);
+ engine.sensorEventQueue = ASensorManager_createEventQueue(engine.sensorManager,
+ state->looper, LOOPER_ID_USER, NULL, NULL);
+
+
+ ANativeActivity_setWindowFlags(state->activity,AWINDOW_FLAG_FULLSCREEN|AWINDOW_FLAG_KEEP_SCREEN_ON,0);
+
+ state->activity->vm->AttachCurrentThread(&engine.jni, NULL);
+
+
+
+ // loop waiting for stuff to do.
+
+ while (1) {
+ // Read all pending events.
+ int ident;
+ int events;
+ struct android_poll_source* source;
+
+ // If not animating, we will block forever waiting for events.
+ // If animating, we loop until all events are read, then continue
+ // to draw the next frame of animation.
+
+ int nullmax=50;
+ while ((ident=ALooper_pollAll(engine.animating ? 0 : -1, NULL, &events,
+ (void**)&source)) >= 0) {
+
+ // Process this event.
+
+ if (source != NULL) {
+ // LOGI("process\n");
+ source->process(state, source);
+ } else {
+ nullmax--;
+ if (nullmax<0)
+ break;
+ }
+
+ // If a sensor has data, process it now.
+ // LOGI("events\n");
+ if (ident == LOOPER_ID_USER) {
+ if (engine.accelerometerSensor != NULL) {
+ ASensorEvent event;
+ while (ASensorEventQueue_getEvents(engine.sensorEventQueue,
+ &event, 1) > 0) {
+
+
+ if (engine.os) {
+ engine.os->process_accelerometer(Vector3(event.acceleration.x, event.acceleration.y,
+ event.acceleration.z));
+
+ }
+
+ }
+ }
+ }
+
+ // Check if we are exiting.
+ if (state->destroyRequested != 0) {
+ if (engine.os) {
+ engine.os->main_loop_request_quit();
+ }
+ state->destroyRequested=0;
+ }
+
+ if (engine.requested_quit) {
+ engine_term_display(&engine);
+ exit(0);
+ return;
+ }
+
+// LOGI("end\n");
+
+
+ }
+
+// LOGI("engine animating? %i\n",engine.animating);
+
+ if (engine.animating) {
+ //do os render
+
+ engine_draw_frame(&engine);
+ //LOGI("TERM WINDOW");
+
+ }
+ }
+
+}
+
+
+
+
+JNIEXPORT void JNICALL Java_com_android_godot_Godot_registerSingleton(JNIEnv * env, jobject obj, jstring name,jobject p_object){
+
+ String singname = env->GetStringUTFChars( name, NULL );
+ JNISingleton *s = memnew( JNISingleton );
+ s->update_env(env);
+ s->set_instance(env->NewGlobalRef(p_object));
+ jni_singletons[singname]=s;
+
+ Globals::get_singleton()->add_singleton(Globals::Singleton(singname,s));
+
+}
+
+
+static Variant::Type get_jni_type(const String& p_type) {
+
+ static struct {
+ const char *name;
+ Variant::Type type;
+ } _type_to_vtype[]={
+ {"void",Variant::NIL},
+ {"boolean",Variant::BOOL},
+ {"int",Variant::INT},
+ {"float",Variant::REAL},
+ {"java.lang.String",Variant::STRING},
+ {"[I",Variant::INT_ARRAY},
+ {"[F",Variant::REAL_ARRAY},
+ {"[java.lang.String",Variant::STRING_ARRAY},
+ {NULL,Variant::NIL}
+ };
+
+ int idx=0;
+
+ while (_type_to_vtype[idx].name) {
+
+ if (p_type==_type_to_vtype[idx].name)
+ return _type_to_vtype[idx].type;
+
+ idx++;
+ }
+
+ return Variant::NIL;
+}
+
+
+static const char* get_jni_sig(const String& p_type) {
+
+ static struct {
+ const char *name;
+ const char *sig;
+ } _type_to_vtype[]={
+ {"void","V"},
+ {"boolean","Z"},
+ {"int","I"},
+ {"float","F"},
+ {"java.lang.String","Ljava/lang/String;"},
+ {"[I","[I"},
+ {"[F","[F"},
+ {"[java.lang.String","[Ljava/lang/String;"},
+ {NULL,"V"}
+ };
+
+ int idx=0;
+
+ while (_type_to_vtype[idx].name) {
+
+ if (p_type==_type_to_vtype[idx].name)
+ return _type_to_vtype[idx].sig;
+
+ idx++;
+ }
+
+
+ return "";
+}
+
+JNIEXPORT jstring JNICALL Java_com_android_godot_Godot_getGlobal(JNIEnv * env, jobject obj, jstring path) {
+
+ String js = env->GetStringUTFChars( path, NULL );
+
+ return env->NewStringUTF(Globals::get_singleton()->get(js).operator String().utf8().get_data());
+
+
+}
+
+
+
+JNIEXPORT void JNICALL Java_com_android_godot_Godot_registerMethod(JNIEnv * env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args){
+
+ String singname = env->GetStringUTFChars( sname, NULL );
+
+ ERR_FAIL_COND(!jni_singletons.has(singname));
+
+ JNISingleton *s = jni_singletons.get(singname);
+
+
+ String mname = env->GetStringUTFChars( name, NULL );
+ String retval = env->GetStringUTFChars( ret, NULL );
+ Vector<Variant::Type> types;
+ String cs="(";
+
+
+ int stringCount = env->GetArrayLength(args);
+
+ print_line("Singl: "+singname+" Method: "+mname+" RetVal: "+retval);
+ for (int i=0; i<stringCount; i++) {
+
+ jstring string = (jstring) env->GetObjectArrayElement(args, i);
+ const char *rawString = env->GetStringUTFChars(string, 0);
+ types.push_back(get_jni_type(String(rawString)));
+ cs+=get_jni_sig(String(rawString));
+ }
+
+ cs+=")";
+ cs+=get_jni_sig(retval);
+ jclass cls = env->GetObjectClass(s->get_instance());
+ print_line("METHOD: "+mname+" sig: "+cs);
+ jmethodID mid = env->GetMethodID(cls, mname.ascii().get_data(), cs.ascii().get_data());
+ if (!mid) {
+
+ print_line("FAILED GETTING METHOID "+mname);
+ }
+
+ s->add_method(mname,mid,types,get_jni_type(retval));
+
+
+}
+
+#endif
diff --git a/platform/android/java/ant.properties b/platform/android/java/ant.properties
new file mode 100644
index 0000000000..950b8b0199
--- /dev/null
+++ b/platform/android/java/ant.properties
@@ -0,0 +1,22 @@
+# This file is used to override default values used by the Ant build system.
+#
+# This file must be checked into Version Control Systems, as it is
+# integral to the build system of your project.
+
+# This file is only used by the Ant script.
+
+# You can use this to override default values such as
+# 'source.dir' for the location of your java source folder and
+# 'out.dir' for the location of your output folder.
+
+# You can also use it define how the release builds are signed by declaring
+# the following properties:
+# 'key.store' for the location of your keystore and
+# 'key.alias' for the name of the key to use.
+# The password will be asked during the build when you use the 'release' target.
+
+key.store=my-release-key.keystore
+key.alias=mykey
+
+key.store.password=123456
+key.alias.password=123456
diff --git a/platform/android/java/build.properties b/platform/android/java/build.properties
new file mode 100644
index 0000000000..ee52d86d94
--- /dev/null
+++ b/platform/android/java/build.properties
@@ -0,0 +1,17 @@
+# This file is used to override default values used by the Ant build system.
+#
+# This file must be checked in Version Control Systems, as it is
+# integral to the build system of your project.
+
+# This file is only used by the Ant script.
+
+# You can use this to override default values such as
+# 'source.dir' for the location of your java source folder and
+# 'out.dir' for the location of your output folder.
+
+# You can also use it define how the release builds are signed by declaring
+# the following properties:
+# 'key.store' for the location of your keystore and
+# 'key.alias' for the name of the key to use.
+# The password will be asked during the build when you use the 'release' target.
+
diff --git a/platform/android/java/build.xml b/platform/android/java/build.xml
new file mode 100644
index 0000000000..424e2827dc
--- /dev/null
+++ b/platform/android/java/build.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="Godot" default="help">
+
+ <!-- The local.properties file is created and updated by the 'android' tool.
+ It contains the path to the SDK. It should *NOT* be checked into
+ Version Control Systems. -->
+ <property file="local.properties" />
+
+ <!-- The ant.properties file can be created by you. It is only edited by the
+ 'android' tool to add properties to it.
+ This is the place to change some Ant specific build properties.
+ Here are some properties you may want to change/update:
+
+ source.dir
+ The name of the source directory. Default is 'src'.
+ out.dir
+ The name of the output directory. Default is 'bin'.
+
+ For other overridable properties, look at the beginning of the rules
+ files in the SDK, at tools/ant/build.xml
+
+ Properties related to the SDK location or the project target should
+ be updated using the 'android' tool with the 'update' action.
+
+ This file is an integral part of the build system for your
+ application and should be checked into Version Control Systems.
+
+ -->
+ <property file="ant.properties" />
+
+ <!-- if sdk.dir was not set from one of the property file, then
+ get it from the ANDROID_HOME env var.
+ This must be done before we load project.properties since
+ the proguard config can use sdk.dir -->
+ <property environment="env" />
+ <condition property="sdk.dir" value="${env.ANDROID_HOME}">
+ <isset property="env.ANDROID_HOME" />
+ </condition>
+
+ <!-- The project.properties file is created and updated by the 'android'
+ tool, as well as ADT.
+
+ This contains project specific properties such as project target, and library
+ dependencies. Lower level build properties are stored in ant.properties
+ (or in .classpath for Eclipse projects).
+
+ This file is an integral part of the build system for your
+ application and should be checked into Version Control Systems. -->
+ <loadproperties srcFile="project.properties" />
+
+ <!-- quick check on sdk.dir -->
+ <fail
+ message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
+ unless="sdk.dir"
+ />
+
+ <!--
+ Import per project custom build rules if present at the root of the project.
+ This is the place to put custom intermediary targets such as:
+ -pre-build
+ -pre-compile
+ -post-compile (This is typically used for code obfuscation.
+ Compiled code location: ${out.classes.absolute.dir}
+ If this is not done in place, override ${out.dex.input.absolute.dir})
+ -post-package
+ -post-build
+ -pre-clean
+ -->
+ <import file="custom_rules.xml" optional="true" />
+
+ <!-- Import the actual build file.
+
+ To customize existing targets, there are two options:
+ - Customize only one target:
+ - copy/paste the target into this file, *before* the
+ <import> task.
+ - customize it to your needs.
+ - Customize the whole content of build.xml
+ - copy/paste the content of the rules files (minus the top node)
+ into this file, replacing the <import> task.
+ - customize to your needs.
+
+ ***********************
+ ****** IMPORTANT ******
+ ***********************
+ In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
+ in order to avoid having your file be overridden by tools such as "android update project"
+ -->
+ <!-- version-tag: 1 -->
+ <import file="${sdk.dir}/tools/ant/build.xml" />
+
+</project>
diff --git a/platform/android/java/default.properties b/platform/android/java/default.properties
new file mode 100644
index 0000000000..e2e8061f26
--- /dev/null
+++ b/platform/android/java/default.properties
@@ -0,0 +1,11 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-8
diff --git a/platform/android/java/my-release-key.keystore b/platform/android/java/my-release-key.keystore
new file mode 100644
index 0000000000..410cccd865
--- /dev/null
+++ b/platform/android/java/my-release-key.keystore
Binary files differ
diff --git a/platform/android/java/proguard-project.txt b/platform/android/java/proguard-project.txt
new file mode 100644
index 0000000000..f2fe1559a2
--- /dev/null
+++ b/platform/android/java/proguard-project.txt
@@ -0,0 +1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
diff --git a/platform/android/java/proguard.cfg b/platform/android/java/proguard.cfg
new file mode 100644
index 0000000000..12dd0392c0
--- /dev/null
+++ b/platform/android/java/proguard.cfg
@@ -0,0 +1,36 @@
+-optimizationpasses 5
+-dontusemixedcaseclassnames
+-dontskipnonpubliclibraryclasses
+-dontpreverify
+-verbose
+-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
+
+-keep public class * extends android.app.Activity
+-keep public class * extends android.app.Application
+-keep public class * extends android.app.Service
+-keep public class * extends android.content.BroadcastReceiver
+-keep public class * extends android.content.ContentProvider
+-keep public class * extends android.app.backup.BackupAgentHelper
+-keep public class * extends android.preference.Preference
+-keep public class com.android.vending.licensing.ILicensingService
+
+-keepclasseswithmembernames class * {
+ native <methods>;
+}
+
+-keepclasseswithmembernames class * {
+ public <init>(android.content.Context, android.util.AttributeSet);
+}
+
+-keepclasseswithmembernames class * {
+ public <init>(android.content.Context, android.util.AttributeSet, int);
+}
+
+-keepclassmembers enum * {
+ public static **[] values();
+ public static ** valueOf(java.lang.String);
+}
+
+-keep class * implements android.os.Parcelable {
+ public static final android.os.Parcelable$Creator *;
+}
diff --git a/platform/android/java/res/drawable/icon.png b/platform/android/java/res/drawable/icon.png
new file mode 100644
index 0000000000..050a1cf930
--- /dev/null
+++ b/platform/android/java/res/drawable/icon.png
Binary files differ
diff --git a/platform/android/java/res/values-ar/strings.xml b/platform/android/java/res/values-ar/strings.xml
new file mode 100644
index 0000000000..9f3dc6d6ac
--- /dev/null
+++ b/platform/android/java/res/values-ar/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-ar</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-bg/strings.xml b/platform/android/java/res/values-bg/strings.xml
new file mode 100644
index 0000000000..bd8109277e
--- /dev/null
+++ b/platform/android/java/res/values-bg/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-bg</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-ca/strings.xml b/platform/android/java/res/values-ca/strings.xml
new file mode 100644
index 0000000000..494cb88468
--- /dev/null
+++ b/platform/android/java/res/values-ca/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-ca</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-cs/strings.xml b/platform/android/java/res/values-cs/strings.xml
new file mode 100644
index 0000000000..30ce00f895
--- /dev/null
+++ b/platform/android/java/res/values-cs/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-cs</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-da/strings.xml b/platform/android/java/res/values-da/strings.xml
new file mode 100644
index 0000000000..4c2a1cf0f4
--- /dev/null
+++ b/platform/android/java/res/values-da/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-da</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-de/strings.xml b/platform/android/java/res/values-de/strings.xml
new file mode 100644
index 0000000000..52946d4cce
--- /dev/null
+++ b/platform/android/java/res/values-de/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-de</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-el/strings.xml b/platform/android/java/res/values-el/strings.xml
new file mode 100644
index 0000000000..181dc51762
--- /dev/null
+++ b/platform/android/java/res/values-el/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-el</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-en/strings.xml b/platform/android/java/res/values-en/strings.xml
new file mode 100644
index 0000000000..976a565013
--- /dev/null
+++ b/platform/android/java/res/values-en/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-en</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-es-rES/strings.xml b/platform/android/java/res/values-es-rES/strings.xml
new file mode 100644
index 0000000000..73f63a08f8
--- /dev/null
+++ b/platform/android/java/res/values-es-rES/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-es_ES</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-es/strings.xml b/platform/android/java/res/values-es/strings.xml
new file mode 100644
index 0000000000..07b718a641
--- /dev/null
+++ b/platform/android/java/res/values-es/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-es</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-fi/strings.xml b/platform/android/java/res/values-fi/strings.xml
new file mode 100644
index 0000000000..323d82aff1
--- /dev/null
+++ b/platform/android/java/res/values-fi/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-fi</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-fr/strings.xml b/platform/android/java/res/values-fr/strings.xml
new file mode 100644
index 0000000000..32bead2661
--- /dev/null
+++ b/platform/android/java/res/values-fr/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-fr</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-he/strings.xml b/platform/android/java/res/values-he/strings.xml
new file mode 100644
index 0000000000..f52ede2085
--- /dev/null
+++ b/platform/android/java/res/values-he/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-he</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-hi/strings.xml b/platform/android/java/res/values-hi/strings.xml
new file mode 100644
index 0000000000..8aab2a8c63
--- /dev/null
+++ b/platform/android/java/res/values-hi/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-hi</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-hr/strings.xml b/platform/android/java/res/values-hr/strings.xml
new file mode 100644
index 0000000000..caf55e2241
--- /dev/null
+++ b/platform/android/java/res/values-hr/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-hr</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-hu/strings.xml b/platform/android/java/res/values-hu/strings.xml
new file mode 100644
index 0000000000..e7f9e51226
--- /dev/null
+++ b/platform/android/java/res/values-hu/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-hu</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-id/strings.xml b/platform/android/java/res/values-id/strings.xml
new file mode 100644
index 0000000000..9e9a8b0c03
--- /dev/null
+++ b/platform/android/java/res/values-id/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-id</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-it/strings.xml b/platform/android/java/res/values-it/strings.xml
new file mode 100644
index 0000000000..1f5e5a049e
--- /dev/null
+++ b/platform/android/java/res/values-it/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-it</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-ja/strings.xml b/platform/android/java/res/values-ja/strings.xml
new file mode 100644
index 0000000000..7f85f57df7
--- /dev/null
+++ b/platform/android/java/res/values-ja/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-ja</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-ko/strings.xml b/platform/android/java/res/values-ko/strings.xml
new file mode 100644
index 0000000000..6d27498af8
--- /dev/null
+++ b/platform/android/java/res/values-ko/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-ko</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-lt/strings.xml b/platform/android/java/res/values-lt/strings.xml
new file mode 100644
index 0000000000..6e3677fde7
--- /dev/null
+++ b/platform/android/java/res/values-lt/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-lt</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-lv/strings.xml b/platform/android/java/res/values-lv/strings.xml
new file mode 100644
index 0000000000..701fc271ac
--- /dev/null
+++ b/platform/android/java/res/values-lv/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-lv</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-nb/strings.xml b/platform/android/java/res/values-nb/strings.xml
new file mode 100644
index 0000000000..73147ca1af
--- /dev/null
+++ b/platform/android/java/res/values-nb/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-nb</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-nl/strings.xml b/platform/android/java/res/values-nl/strings.xml
new file mode 100644
index 0000000000..e501928a35
--- /dev/null
+++ b/platform/android/java/res/values-nl/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-nl</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-pl/strings.xml b/platform/android/java/res/values-pl/strings.xml
new file mode 100644
index 0000000000..ea5da73b6f
--- /dev/null
+++ b/platform/android/java/res/values-pl/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-pl</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-pt/strings.xml b/platform/android/java/res/values-pt/strings.xml
new file mode 100644
index 0000000000..bdda7cd2c7
--- /dev/null
+++ b/platform/android/java/res/values-pt/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-pt</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-ro/strings.xml b/platform/android/java/res/values-ro/strings.xml
new file mode 100644
index 0000000000..3686da4c19
--- /dev/null
+++ b/platform/android/java/res/values-ro/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-ro</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-ru/strings.xml b/platform/android/java/res/values-ru/strings.xml
new file mode 100644
index 0000000000..954067658b
--- /dev/null
+++ b/platform/android/java/res/values-ru/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-ru</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-sk/strings.xml b/platform/android/java/res/values-sk/strings.xml
new file mode 100644
index 0000000000..37d1283124
--- /dev/null
+++ b/platform/android/java/res/values-sk/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-sk</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-sl/strings.xml b/platform/android/java/res/values-sl/strings.xml
new file mode 100644
index 0000000000..0bb249c375
--- /dev/null
+++ b/platform/android/java/res/values-sl/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-sl</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-sr/strings.xml b/platform/android/java/res/values-sr/strings.xml
new file mode 100644
index 0000000000..0e83cab1a1
--- /dev/null
+++ b/platform/android/java/res/values-sr/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-sr</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-sv/strings.xml b/platform/android/java/res/values-sv/strings.xml
new file mode 100644
index 0000000000..e3a04ac2ec
--- /dev/null
+++ b/platform/android/java/res/values-sv/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-sv</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-th/strings.xml b/platform/android/java/res/values-th/strings.xml
new file mode 100644
index 0000000000..0aa893b8bf
--- /dev/null
+++ b/platform/android/java/res/values-th/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-th</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-tl/strings.xml b/platform/android/java/res/values-tl/strings.xml
new file mode 100644
index 0000000000..e7e2af4909
--- /dev/null
+++ b/platform/android/java/res/values-tl/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-tl</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-tr/strings.xml b/platform/android/java/res/values-tr/strings.xml
new file mode 100644
index 0000000000..97af1243a6
--- /dev/null
+++ b/platform/android/java/res/values-tr/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-tr</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-uk/strings.xml b/platform/android/java/res/values-uk/strings.xml
new file mode 100644
index 0000000000..3dea6908a9
--- /dev/null
+++ b/platform/android/java/res/values-uk/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-uk</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-vi/strings.xml b/platform/android/java/res/values-vi/strings.xml
new file mode 100644
index 0000000000..a6552130b0
--- /dev/null
+++ b/platform/android/java/res/values-vi/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-vi</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-zh/strings.xml b/platform/android/java/res/values-zh/strings.xml
new file mode 100644
index 0000000000..397e662851
--- /dev/null
+++ b/platform/android/java/res/values-zh/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-zh</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values/strings.xml b/platform/android/java/res/values/strings.xml
new file mode 100644
index 0000000000..3a38d40599
--- /dev/null
+++ b/platform/android/java/res/values/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name</string>
+ <string name="testuf8">元気です</string>
+ <string name="testuf2">元気です元気です元気です</string>
+
+</resources>
diff --git a/platform/android/java/src/com/android/godot/Dictionary.java b/platform/android/java/src/com/android/godot/Dictionary.java
new file mode 100644
index 0000000000..4ed12f5818
--- /dev/null
+++ b/platform/android/java/src/com/android/godot/Dictionary.java
@@ -0,0 +1,80 @@
+/*************************************************************************/
+/* Dictionary.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+package com.android.godot;
+
+import java.util.HashMap;
+import java.util.Set;
+
+
+public class Dictionary extends HashMap<String, Object> {
+
+ protected String[] keys_cache;
+
+ public String[] get_keys() {
+
+ String[] ret = new String[size()];
+ int i=0;
+ Set<String> keys = keySet();
+ for (String key : keys) {
+
+ ret[i] = key;
+ i++;
+ };
+
+ return ret;
+ };
+
+ public Object[] get_values() {
+
+ Object[] ret = new Object[size()];
+ int i=0;
+ Set<String> keys = keySet();
+ for (String key : keys) {
+
+ ret[i] = get(key);
+ i++;
+ };
+
+ return ret;
+ };
+
+ public void set_keys(String[] keys) {
+ keys_cache = keys;
+ };
+
+ public void set_values(Object[] vals) {
+
+ int i=0;
+ for (String key : keys_cache) {
+ put(key, vals[i]);
+ i++;
+ };
+ keys_cache = null;
+ };
+};
diff --git a/platform/android/java/src/com/android/godot/Godot.java b/platform/android/java/src/com/android/godot/Godot.java
new file mode 100644
index 0000000000..cf1545df82
--- /dev/null
+++ b/platform/android/java/src/com/android/godot/Godot.java
@@ -0,0 +1,300 @@
+/*************************************************************************/
+/* Godot.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+package com.android.godot;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.MotionEvent;
+import android.widget.RelativeLayout;
+import android.widget.LinearLayout;
+import android.view.ViewGroup.LayoutParams;
+
+
+import android.app.*;
+import android.content.*;
+import android.view.*;
+import android.view.inputmethod.InputMethodManager;
+import android.os.*;
+import android.util.Log;
+import android.graphics.*;
+import android.text.method.*;
+import android.text.*;
+import android.media.*;
+import android.hardware.*;
+import android.content.*;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.ArrayList;
+import android.provider.Settings.Secure;
+
+
+public class Godot extends Activity implements SensorEventListener
+{
+
+ static public class SingletonBase {
+
+ protected void registerClass(String p_name, String[] p_methods) {
+
+ GodotLib.singleton(p_name,this);
+
+ Class clazz = getClass();
+ Method[] methods = clazz.getDeclaredMethods();
+ for (Method method : methods) {
+ boolean found=false;
+ System.out.printf("METHOD: %s\n",method.getName());
+
+ for (String s : p_methods) {
+ System.out.printf("METHOD CMP WITH: %s\n",s);
+ if (s.equals(method.getName())) {
+ found=true;
+ System.out.printf("METHOD CMP VALID");
+ break;
+ }
+ }
+ if (!found)
+ continue;
+
+ System.out.printf("METHOD FOUND: %s\n",method.getName());
+
+ List<String> ptr = new ArrayList<String>();
+
+ Class[] paramTypes = method.getParameterTypes();
+ for (Class c : paramTypes) {
+ ptr.add(c.getName());
+ }
+
+ String[] pt = new String[ptr.size()];
+ ptr.toArray(pt);
+
+ GodotLib.method(p_name,method.getName(),method.getReturnType().getName(),pt);
+
+
+ }
+ }
+
+ public void registerMethods() {}
+ }
+
+/*
+ protected List<SingletonBase> singletons = new ArrayList<SingletonBase>();
+ protected void instanceSingleton(SingletonBase s) {
+
+ s.registerMethods();
+ singletons.add(s);
+ }
+
+*/
+
+ public GodotView mView;
+
+ private SensorManager mSensorManager;
+ private Sensor mAccelerometer;
+
+ public RelativeLayout layout;
+
+
+ static public GodotIO io;
+
+ public static void setWindowTitle(String title) {
+ //setTitle(title);
+ }
+
+ public interface ResultCallback {
+ public void callback(int requestCode, int resultCode, Intent data);
+ };
+ public ResultCallback result_callback;
+
+ @Override protected void onActivityResult (int requestCode, int resultCode, Intent data) {
+ if (result_callback != null) {
+ result_callback.callback(requestCode, resultCode, data);
+ result_callback = null;
+ };
+ };
+
+ public void onVideoInit(boolean use_gl2) {
+
+// mView = new GodotView(getApplication(),io,use_gl2);
+// setContentView(mView);
+
+ layout = new RelativeLayout(this);
+ layout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
+ setContentView(layout);
+ mView = new GodotView(getApplication(),io,use_gl2, this);
+ layout.addView(mView,new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
+ mView.setKeepScreenOn(true);
+
+ }
+
+ @Override protected void onCreate(Bundle icicle) {
+
+
+ super.onCreate(icicle);
+
+
+
+ Window window = getWindow();
+ window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+ | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+ io = new GodotIO(this);
+ io.unique_id = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
+ GodotLib.io=io;
+ GodotLib.initialize(this,io.needsReloadHooks());
+ mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
+ mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
+ mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
+
+ result_callback = null;
+
+ // instanceSingleton( new GodotFacebook(this) );
+
+
+ }
+
+ @Override protected void onPause() {
+ super.onPause();
+ mView.onPause();
+ mSensorManager.unregisterListener(this);
+ GodotLib.focusout();
+
+ }
+
+ @Override protected void onResume() {
+ super.onResume();
+ mView.onResume();
+ mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
+ GodotLib.focusin();
+ }
+
+ @Override public void onSensorChanged(SensorEvent event) {
+ float x = event.values[0];
+ float y = event.values[1];
+ float z = event.values[2];
+ GodotLib.accelerometer(x,y,z);
+ }
+
+ @Override public final void onAccuracyChanged(Sensor sensor, int accuracy) {
+ // Do something here if sensor accuracy changes.
+ }
+
+/*
+ @Override public boolean dispatchKeyEvent(KeyEvent event) {
+
+ if (event.getKeyCode()==KeyEvent.KEYCODE_BACK) {
+
+ System.out.printf("** BACK REQUEST!\n");
+
+ GodotLib.quit();
+ return true;
+ }
+ System.out.printf("** OTHER KEY!\n");
+
+ return false;
+ }
+*/
+
+ @Override public void onBackPressed() {
+
+ GodotLib.quit();
+ }
+
+ public void forceQuit() {
+
+ System.exit(0);
+ }
+
+
+ //@Override public boolean dispatchTouchEvent (MotionEvent event) {
+ public boolean gotTouchEvent(MotionEvent event) {
+
+ super.onTouchEvent(event);
+ int evcount=event.getPointerCount();
+ if (evcount==0)
+ return true;
+
+ int[] arr = new int[event.getPointerCount()*3];
+
+ for(int i=0;i<event.getPointerCount();i++) {
+
+ arr[i*3+0]=(int)event.getPointerId(i);
+ arr[i*3+1]=(int)event.getX(i);
+ arr[i*3+2]=(int)event.getY(i);
+ }
+
+ //System.out.printf("gaction: %d\n",event.getAction());
+ switch(event.getAction()&MotionEvent.ACTION_MASK) {
+
+ case MotionEvent.ACTION_DOWN: {
+ GodotLib.touch(0,0,evcount,arr);
+ //System.out.printf("action down at: %f,%f\n", event.getX(),event.getY());
+ } break;
+ case MotionEvent.ACTION_MOVE: {
+ GodotLib.touch(1,0,evcount,arr);
+ //for(int i=0;i<event.getPointerCount();i++) {
+ // System.out.printf("%d - moved to: %f,%f\n",i, event.getX(i),event.getY(i));
+ //}
+ } break;
+ case MotionEvent.ACTION_POINTER_UP: {
+ int pointer_idx = event.getActionIndex();
+ GodotLib.touch(4,pointer_idx,evcount,arr);
+ //System.out.printf("%d - s.up at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
+ } break;
+ case MotionEvent.ACTION_POINTER_DOWN: {
+ int pointer_idx = event.getActionIndex();
+ GodotLib.touch(3,pointer_idx,evcount,arr);
+ //System.out.printf("%d - s.down at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
+ } break;
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP: {
+ GodotLib.touch(2,0,evcount,arr);
+ //for(int i=0;i<event.getPointerCount();i++) {
+ // System.out.printf("%d - up! %f,%f\n",i, event.getX(i),event.getY(i));
+ //}
+ } break;
+
+ }
+ return true;
+ }
+
+ @Override public boolean onKeyUp(int keyCode, KeyEvent event) {
+ GodotLib.key(event.getUnicodeChar(0), false);
+ return super.onKeyUp(keyCode, event);
+ };
+
+ @Override public boolean onKeyDown(int keyCode, KeyEvent event) {
+ GodotLib.key(event.getUnicodeChar(0), true);
+ return super.onKeyDown(keyCode, event);
+ };
+
+
+ // Audio
+
+
+}
diff --git a/platform/android/java/src/com/android/godot/GodotIO.java b/platform/android/java/src/com/android/godot/GodotIO.java
new file mode 100644
index 0000000000..1f3967cb8f
--- /dev/null
+++ b/platform/android/java/src/com/android/godot/GodotIO.java
@@ -0,0 +1,514 @@
+/*************************************************************************/
+/* GodotIO.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+package com.android.godot;
+import java.util.HashMap;
+import java.util.Locale;
+import android.net.Uri;
+import android.content.Intent;
+import android.content.res.AssetManager;
+import java.io.InputStream;
+import java.io.IOException;
+import android.app.*;
+import android.content.*;
+import android.view.*;
+import android.view.inputmethod.InputMethodManager;
+import android.os.*;
+import android.util.Log;
+import android.graphics.*;
+import android.text.method.*;
+import android.text.*;
+import android.media.*;
+import android.hardware.*;
+import android.content.*;
+import android.content.pm.ActivityInfo;
+//android.os.Build
+
+// Wrapper for native library
+
+public class GodotIO {
+
+
+ AssetManager am;
+ Activity activity;
+
+ final int SCREEN_LANDSCAPE=0;
+ final int SCREEN_PORTRAIT=1;
+ final int SCREEN_REVERSE_LANDSCAPE=2;
+ final int SCREEN_REVERSE_PORTRAIT=3;
+ final int SCREEN_SENSOR_LANDSCAPE=4;
+ final int SCREEN_SENSOR_PORTRAIT=5;
+ final int SCREEN_SENSOR=6;
+
+ /////////////////////////
+ /// FILES
+ /////////////////////////
+
+ public int last_file_id=1;
+
+ class AssetData {
+
+
+ public boolean eof=false;
+ public String path;
+ public InputStream is;
+ public int len;
+ public int pos;
+ }
+
+
+ HashMap<Integer,AssetData> streams;
+
+
+ public int file_open(String path,boolean write) {
+
+ //System.out.printf("file_open: Attempt to Open %s\n",path);
+
+ if (write)
+ return -1;
+
+
+ AssetData ad = new AssetData();
+
+ try {
+ ad.is = am.open(path);
+
+ } catch (Exception e) {
+
+ //System.out.printf("Exception on file_open: %s\n",e);
+ return -1;
+ }
+
+ try {
+ ad.len=ad.is.available();
+ } catch (Exception e) {
+
+ System.out.printf("Exception availabling on file_open: %s\n",e);
+ return -1;
+ }
+
+ ad.path=path;
+ ad.pos=0;
+ ++last_file_id;
+ streams.put(last_file_id,ad);
+
+ return last_file_id;
+ }
+ public int file_get_size(int id) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_get_size: Invalid file id: %d\n",id);
+ return -1;
+ }
+
+ return streams.get(id).len;
+
+ }
+ public void file_seek(int id,int bytes) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_get_size: Invalid file id: %d\n",id);
+ return;
+ }
+ //seek sucks
+ AssetData ad = streams.get(id);
+ if (bytes>ad.len)
+ bytes=ad.len;
+ if (bytes<0)
+ bytes=0;
+
+ try {
+
+ if (bytes > (int)ad.pos) {
+ int todo=bytes-(int)ad.pos;
+ while(todo>0) {
+ todo-=ad.is.skip(todo);
+ }
+ ad.pos=bytes;
+ } else if (bytes<(int)ad.pos) {
+
+ ad.is=am.open(ad.path);
+
+ ad.pos=bytes;
+ int todo=bytes;
+ while(todo>0) {
+ todo-=ad.is.skip(todo);
+ }
+ }
+
+ ad.eof=false;
+ } catch (IOException e) {
+
+ System.out.printf("Exception on file_seek: %s\n",e);
+ return;
+ }
+
+
+ }
+
+ public int file_tell(int id) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_read: Can't tell eof for invalid file id: %d\n",id);
+ return 0;
+ }
+
+ AssetData ad = streams.get(id);
+ return ad.pos;
+ }
+ public boolean file_eof(int id) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_read: Can't check eof for invalid file id: %d\n",id);
+ return false;
+ }
+
+ AssetData ad = streams.get(id);
+ return ad.eof;
+ }
+
+ public byte[] file_read(int id, int bytes) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_read: Can't read invalid file id: %d\n",id);
+ return new byte[0];
+ }
+
+
+ AssetData ad = streams.get(id);
+
+ if (ad.pos + bytes > ad.len) {
+
+ bytes=ad.len-ad.pos;
+ ad.eof=true;
+ }
+
+
+ if (bytes==0) {
+
+ return new byte[0];
+ }
+
+
+
+ byte[] buf1=new byte[bytes];
+ int r=0;
+ try {
+ r = ad.is.read(buf1);
+ } catch (IOException e) {
+
+ System.out.printf("Exception on file_read: %s\n",e);
+ return new byte[bytes];
+ }
+
+ if (r==0) {
+ return new byte[0];
+ }
+
+ ad.pos+=r;
+
+ if (r<bytes) {
+
+ byte[] buf2=new byte[r];
+ for(int i=0;i<r;i++)
+ buf2[i]=buf1[i];
+ return buf2;
+ } else {
+
+ return buf1;
+ }
+
+ }
+
+ public void file_close(int id) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_close: Can't close invalid file id: %d\n",id);
+ return;
+ }
+
+ streams.remove(id);
+
+ }
+
+
+ /////////////////////////
+ /// DIRECTORIES
+ /////////////////////////
+
+
+ class AssetDir {
+
+ public String[] files;
+ public int current;
+ }
+
+ public int last_dir_id=1;
+
+ HashMap<Integer,AssetDir> dirs;
+
+ public int dir_open(String path) {
+
+ AssetDir ad = new AssetDir();
+ ad.current=0;
+
+ try {
+ ad.files = am.list(path);
+ } catch (IOException e) {
+
+ System.out.printf("Exception on dir_open: %s\n",e);
+ return -1;
+ }
+
+ ++last_dir_id;
+ dirs.put(last_dir_id,ad);
+
+ return last_dir_id;
+
+ }
+
+ public String dir_next(int id) {
+
+ if (!dirs.containsKey(id)) {
+ System.out.printf("dir_next: invalid dir id: %d\n",id);
+ return "";
+ }
+
+ AssetDir ad = dirs.get(id);
+ if (ad.current>=ad.files.length)
+ return "";
+ String r = ad.files[ad.current];
+ ad.current++;
+ return r;
+
+ }
+
+ public void dir_close(int id) {
+
+ if (!dirs.containsKey(id)) {
+ System.out.printf("dir_close: invalid dir id: %d\n",id);
+ return;
+ }
+
+ dirs.remove(id);
+ }
+
+
+
+ GodotIO(Activity p_activity) {
+
+ am=p_activity.getAssets();
+ activity=p_activity;
+ streams=new HashMap<Integer,AssetData>();
+ dirs=new HashMap<Integer,AssetDir>();
+
+
+ }
+
+
+ /////////////////////////
+ // AUDIO
+ /////////////////////////
+
+ private Object buf;
+ private Thread mAudioThread;
+ private AudioTrack mAudioTrack;
+
+ public Object audioInit(int sampleRate, int desiredFrames) {
+ int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
+ int frameSize = 4;
+
+ System.out.printf("audioInit: initializing audio:\n");
+
+ //Log.v("Godot", "Godot audio: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + ((float)sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer");
+
+ // Let the user pick a larger buffer if they really want -- but ye
+ // gods they probably shouldn't, the minimums are horrifyingly high
+ // latency already
+ desiredFrames = Math.max(desiredFrames, (AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
+
+ mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
+ channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM);
+
+ audioStartThread();
+
+ //Log.v("Godot", "Godot audio: got " + ((mAudioTrack.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioTrack.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + ((float)mAudioTrack.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer");
+
+ buf = new short[desiredFrames * 2];
+ return buf;
+ }
+
+ public void audioStartThread() {
+ mAudioThread = new Thread(new Runnable() {
+ public void run() {
+ mAudioTrack.play();
+ GodotLib.audio();
+ }
+ });
+
+ // I'd take REALTIME if I could get it!
+ mAudioThread.setPriority(Thread.MAX_PRIORITY);
+ mAudioThread.start();
+ }
+
+ public void audioWriteShortBuffer(short[] buffer) {
+ for (int i = 0; i < buffer.length; ) {
+ int result = mAudioTrack.write(buffer, i, buffer.length - i);
+ if (result > 0) {
+ i += result;
+ } else if (result == 0) {
+ try {
+ Thread.sleep(1);
+ } catch(InterruptedException e) {
+ // Nom nom
+ }
+ } else {
+ Log.w("Godot", "Godot audio: error return from write(short)");
+ return;
+ }
+ }
+ }
+
+
+
+ public void audioQuit() {
+ if (mAudioThread != null) {
+ try {
+ mAudioThread.join();
+ } catch(Exception e) {
+ Log.v("Godot", "Problem stopping audio thread: " + e);
+ }
+ mAudioThread = null;
+
+ //Log.v("Godot", "Finished waiting for audio thread");
+ }
+
+ if (mAudioTrack != null) {
+ mAudioTrack.stop();
+ mAudioTrack = null;
+ }
+ }
+
+ public void audioPause(boolean p_pause) {
+
+ if (p_pause)
+ mAudioTrack.pause();
+ else
+ mAudioTrack.play();
+ }
+
+ /////////////////////////
+ // MISCELANEOUS OS IO
+ /////////////////////////
+
+
+
+ public int openURI(String p_uri) {
+
+ try {
+ Log.v("MyApp", "TRYING TO OPEN URI: " + p_uri);
+ Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(p_uri));
+ activity.startActivity(myIntent);
+ return 0;
+ } catch (ActivityNotFoundException e) {
+
+ return 1;
+ }
+ }
+
+ public String getDataDir() {
+
+ return activity.getFilesDir().getAbsolutePath();
+ }
+
+ public String getLocale() {
+
+ return Locale.getDefault().toString();
+ }
+
+ public String getModel() {
+ return Build.MODEL;
+ }
+
+ public boolean needsReloadHooks() {
+
+ return android.os.Build.VERSION.SDK_INT < 11;
+ }
+
+ public void showKeyboard(String p_existing_text) {
+
+ InputMethodManager inputMgr = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE);
+ inputMgr.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
+ };
+
+ public void hideKeyboard() {
+
+ InputMethodManager inputMgr = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE);
+ inputMgr.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
+ };
+
+ public void setScreenOrientation(int p_orientation) {
+
+ switch(p_orientation) {
+
+ case SCREEN_LANDSCAPE: {
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+ } break;
+ case SCREEN_PORTRAIT: {
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+ } break;
+ case SCREEN_REVERSE_LANDSCAPE: {
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
+ } break;
+ case SCREEN_REVERSE_PORTRAIT: {
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
+ } break;
+ case SCREEN_SENSOR_LANDSCAPE: {
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
+ } break;
+ case SCREEN_SENSOR_PORTRAIT: {
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
+ } break;
+ case SCREEN_SENSOR: {
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
+ } break;
+
+ }
+ };
+
+ protected static final String PREFS_FILE = "device_id.xml";
+ protected static final String PREFS_DEVICE_ID = "device_id";
+
+ public static String unique_id="";
+ public String getUniqueID() {
+
+ return unique_id;
+ }
+
+}
diff --git a/platform/android/java/src/com/android/godot/GodotLib.java b/platform/android/java/src/com/android/godot/GodotLib.java
new file mode 100644
index 0000000000..8d002c5ebc
--- /dev/null
+++ b/platform/android/java/src/com/android/godot/GodotLib.java
@@ -0,0 +1,63 @@
+/*************************************************************************/
+/* GodotLib.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+package com.android.godot;
+
+// Wrapper for native library
+
+public class GodotLib {
+
+
+ public static GodotIO io;
+
+ static {
+ System.loadLibrary("godot_android");
+ }
+
+ /**
+ * @param width the current view width
+ * @param height the current view height
+ */
+
+ public static native void initialize(Godot p_instance,boolean need_reload_hook);
+ public static native void resize(int width, int height,boolean reload);
+ public static native void newcontext();
+ public static native void quit();
+ public static native void step();
+ public static native void touch(int what,int pointer,int howmany, int[] arr);
+ public static native void accelerometer(float x, float y, float z);
+ public static native void key(int p_unicode_char, boolean p_pressed);
+ public static native void focusin();
+ public static native void focusout();
+ public static native void audio();
+ public static native void singleton(String p_name,Object p_object);
+ public static native void method(String p_sname,String p_name,String p_ret,String[] p_params);
+ public static native String getGlobal(String p_key);
+ public static native void callobject(int p_ID, String p_method, Object[] p_params);
+
+}
diff --git a/platform/android/java/src/com/android/godot/GodotView.java b/platform/android/java/src/com/android/godot/GodotView.java
new file mode 100644
index 0000000000..093757bfb0
--- /dev/null
+++ b/platform/android/java/src/com/android/godot/GodotView.java
@@ -0,0 +1,378 @@
+/*************************************************************************/
+/* GodotView.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+package com.android.godot;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.content.ContextWrapper;
+
+import java.io.File;
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * A simple GLSurfaceView sub-class that demonstrate how to perform
+ * OpenGL ES 2.0 rendering into a GL Surface. Note the following important
+ * details:
+ *
+ * - The class must use a custom context factory to enable 2.0 rendering.
+ * See ContextFactory class definition below.
+ *
+ * - The class must use a custom EGLConfigChooser to be able to select
+ * an EGLConfig that supports 2.0. This is done by providing a config
+ * specification to eglChooseConfig() that has the attribute
+ * EGL10.ELG_RENDERABLE_TYPE containing the EGL_OPENGL_ES2_BIT flag
+ * set. See ConfigChooser class definition below.
+ *
+ * - The class must select the surface's format, then choose an EGLConfig
+ * that matches it exactly (with regards to red/green/blue/alpha channels
+ * bit depths). Failure to do so would result in an EGL_BAD_MATCH error.
+ */
+class GodotView extends GLSurfaceView {
+ private static String TAG = "GodotView";
+ private static final boolean DEBUG = false;
+ private static Context ctx;
+
+ private static GodotIO io;
+ private static boolean firsttime=true;
+ private static boolean use_gl2=false;
+
+ private Godot activity;
+
+ public GodotView(Context context,GodotIO p_io,boolean p_use_gl2, Godot p_activity) {
+ super(context);
+ ctx=context;
+ io=p_io;
+ use_gl2=p_use_gl2;
+
+ activity = p_activity;
+
+ if (!p_io.needsReloadHooks()) {
+ //will only work on SDK 11+!!
+ setPreserveEGLContextOnPause(true);
+ }
+
+ init(false, 16, 0);
+ }
+
+ public GodotView(Context context, boolean translucent, int depth, int stencil) {
+ super(context);
+ init(translucent, depth, stencil);
+ }
+
+ @Override public boolean onTouchEvent (MotionEvent event) {
+
+ return activity.gotTouchEvent(event);
+ };
+
+ private void init(boolean translucent, int depth, int stencil) {
+
+ /* By default, GLSurfaceView() creates a RGB_565 opaque surface.
+ * If we want a translucent one, we should change the surface's
+ * format here, using PixelFormat.TRANSLUCENT for GL Surfaces
+ * is interpreted as any 32-bit surface with alpha by SurfaceFlinger.
+ */
+ if (translucent) {
+ this.getHolder().setFormat(PixelFormat.TRANSLUCENT);
+ }
+
+ /* Setup the context factory for 2.0 rendering.
+ * See ContextFactory class definition below
+ */
+ setEGLContextFactory(new ContextFactory());
+
+ /* We need to choose an EGLConfig that matches the format of
+ * our surface exactly. This is going to be done in our
+ * custom config chooser. See ConfigChooser class definition
+ * below.
+ */
+ setEGLConfigChooser( translucent ?
+ new ConfigChooser(8, 8, 8, 8, depth, stencil) :
+ new ConfigChooser(5, 6, 5, 0, depth, stencil) );
+
+ /* Set the renderer responsible for frame rendering */
+ setRenderer(new Renderer());
+ }
+
+ private static class ContextFactory implements GLSurfaceView.EGLContextFactory {
+ private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+ public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {
+ if (use_gl2)
+ Log.w(TAG, "creating OpenGL ES 2.0 context :");
+ else
+ Log.w(TAG, "creating OpenGL ES 1.1 context :");
+
+ checkEglError("Before eglCreateContext", egl);
+ int[] attrib_list2 = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
+ EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, use_gl2?attrib_list2:null);
+ checkEglError("After eglCreateContext", egl);
+ return context;
+ }
+
+ public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {
+ egl.eglDestroyContext(display, context);
+ }
+ }
+
+ private static void checkEglError(String prompt, EGL10 egl) {
+ int error;
+ while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) {
+ Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error));
+ }
+ }
+
+ private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser {
+
+ public ConfigChooser(int r, int g, int b, int a, int depth, int stencil) {
+ mRedSize = r;
+ mGreenSize = g;
+ mBlueSize = b;
+ mAlphaSize = a;
+ mDepthSize = depth;
+ mStencilSize = stencil;
+ }
+
+ /* This EGL config specification is used to specify 2.0 rendering.
+ * We use a minimum size of 4 bits for red/green/blue, but will
+ * perform actual matching in chooseConfig() below.
+ */
+ private static int EGL_OPENGL_ES2_BIT = 4;
+ private static int[] s_configAttribs2 =
+ {
+ EGL10.EGL_RED_SIZE, 4,
+ EGL10.EGL_GREEN_SIZE, 4,
+ EGL10.EGL_BLUE_SIZE, 4,
+ // EGL10.EGL_DEPTH_SIZE, 16,
+ // EGL10.EGL_STENCIL_SIZE, EGL10.EGL_DONT_CARE,
+ EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL10.EGL_NONE
+ };
+ private static int[] s_configAttribs =
+ {
+ EGL10.EGL_RED_SIZE, 4,
+ EGL10.EGL_GREEN_SIZE, 4,
+ EGL10.EGL_BLUE_SIZE, 4,
+ // EGL10.EGL_DEPTH_SIZE, 16,
+ // EGL10.EGL_STENCIL_SIZE, EGL10.EGL_DONT_CARE,
+ EGL10.EGL_NONE
+ };
+
+ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
+
+ /* Get the number of minimally matching EGL configurations
+ */
+ int[] num_config = new int[1];
+ egl.eglChooseConfig(display, use_gl2?s_configAttribs2:s_configAttribs, null, 0, num_config);
+
+ int numConfigs = num_config[0];
+
+ if (numConfigs <= 0) {
+ throw new IllegalArgumentException("No configs match configSpec");
+ }
+
+ /* Allocate then read the array of minimally matching EGL configs
+ */
+ EGLConfig[] configs = new EGLConfig[numConfigs];
+ egl.eglChooseConfig(display, use_gl2?s_configAttribs2:s_configAttribs, configs, numConfigs, num_config);
+
+ if (DEBUG) {
+ printConfigs(egl, display, configs);
+ }
+ /* Now return the "best" one
+ */
+ return chooseConfig(egl, display, configs);
+ }
+
+ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
+ EGLConfig[] configs) {
+ for(EGLConfig config : configs) {
+ int d = findConfigAttrib(egl, display, config,
+ EGL10.EGL_DEPTH_SIZE, 0);
+ int s = findConfigAttrib(egl, display, config,
+ EGL10.EGL_STENCIL_SIZE, 0);
+
+ // We need at least mDepthSize and mStencilSize bits
+ if (d < mDepthSize || s < mStencilSize)
+ continue;
+
+ // We want an *exact* match for red/green/blue/alpha
+ int r = findConfigAttrib(egl, display, config,
+ EGL10.EGL_RED_SIZE, 0);
+ int g = findConfigAttrib(egl, display, config,
+ EGL10.EGL_GREEN_SIZE, 0);
+ int b = findConfigAttrib(egl, display, config,
+ EGL10.EGL_BLUE_SIZE, 0);
+ int a = findConfigAttrib(egl, display, config,
+ EGL10.EGL_ALPHA_SIZE, 0);
+
+ if (r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize)
+ return config;
+ }
+ return null;
+ }
+
+ private int findConfigAttrib(EGL10 egl, EGLDisplay display,
+ EGLConfig config, int attribute, int defaultValue) {
+
+ if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
+ return mValue[0];
+ }
+ return defaultValue;
+ }
+
+ private void printConfigs(EGL10 egl, EGLDisplay display,
+ EGLConfig[] configs) {
+ int numConfigs = configs.length;
+ Log.w(TAG, String.format("%d configurations", numConfigs));
+ for (int i = 0; i < numConfigs; i++) {
+ Log.w(TAG, String.format("Configuration %d:\n", i));
+ printConfig(egl, display, configs[i]);
+ }
+ }
+
+ private void printConfig(EGL10 egl, EGLDisplay display,
+ EGLConfig config) {
+ int[] attributes = {
+ EGL10.EGL_BUFFER_SIZE,
+ EGL10.EGL_ALPHA_SIZE,
+ EGL10.EGL_BLUE_SIZE,
+ EGL10.EGL_GREEN_SIZE,
+ EGL10.EGL_RED_SIZE,
+ EGL10.EGL_DEPTH_SIZE,
+ EGL10.EGL_STENCIL_SIZE,
+ EGL10.EGL_CONFIG_CAVEAT,
+ EGL10.EGL_CONFIG_ID,
+ EGL10.EGL_LEVEL,
+ EGL10.EGL_MAX_PBUFFER_HEIGHT,
+ EGL10.EGL_MAX_PBUFFER_PIXELS,
+ EGL10.EGL_MAX_PBUFFER_WIDTH,
+ EGL10.EGL_NATIVE_RENDERABLE,
+ EGL10.EGL_NATIVE_VISUAL_ID,
+ EGL10.EGL_NATIVE_VISUAL_TYPE,
+ 0x3030, // EGL10.EGL_PRESERVED_RESOURCES,
+ EGL10.EGL_SAMPLES,
+ EGL10.EGL_SAMPLE_BUFFERS,
+ EGL10.EGL_SURFACE_TYPE,
+ EGL10.EGL_TRANSPARENT_TYPE,
+ EGL10.EGL_TRANSPARENT_RED_VALUE,
+ EGL10.EGL_TRANSPARENT_GREEN_VALUE,
+ EGL10.EGL_TRANSPARENT_BLUE_VALUE,
+ 0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB,
+ 0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA,
+ 0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL,
+ 0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL,
+ EGL10.EGL_LUMINANCE_SIZE,
+ EGL10.EGL_ALPHA_MASK_SIZE,
+ EGL10.EGL_COLOR_BUFFER_TYPE,
+ EGL10.EGL_RENDERABLE_TYPE,
+ 0x3042 // EGL10.EGL_CONFORMANT
+ };
+ String[] names = {
+ "EGL_BUFFER_SIZE",
+ "EGL_ALPHA_SIZE",
+ "EGL_BLUE_SIZE",
+ "EGL_GREEN_SIZE",
+ "EGL_RED_SIZE",
+ "EGL_DEPTH_SIZE",
+ "EGL_STENCIL_SIZE",
+ "EGL_CONFIG_CAVEAT",
+ "EGL_CONFIG_ID",
+ "EGL_LEVEL",
+ "EGL_MAX_PBUFFER_HEIGHT",
+ "EGL_MAX_PBUFFER_PIXELS",
+ "EGL_MAX_PBUFFER_WIDTH",
+ "EGL_NATIVE_RENDERABLE",
+ "EGL_NATIVE_VISUAL_ID",
+ "EGL_NATIVE_VISUAL_TYPE",
+ "EGL_PRESERVED_RESOURCES",
+ "EGL_SAMPLES",
+ "EGL_SAMPLE_BUFFERS",
+ "EGL_SURFACE_TYPE",
+ "EGL_TRANSPARENT_TYPE",
+ "EGL_TRANSPARENT_RED_VALUE",
+ "EGL_TRANSPARENT_GREEN_VALUE",
+ "EGL_TRANSPARENT_BLUE_VALUE",
+ "EGL_BIND_TO_TEXTURE_RGB",
+ "EGL_BIND_TO_TEXTURE_RGBA",
+ "EGL_MIN_SWAP_INTERVAL",
+ "EGL_MAX_SWAP_INTERVAL",
+ "EGL_LUMINANCE_SIZE",
+ "EGL_ALPHA_MASK_SIZE",
+ "EGL_COLOR_BUFFER_TYPE",
+ "EGL_RENDERABLE_TYPE",
+ "EGL_CONFORMANT"
+ };
+ int[] value = new int[1];
+ for (int i = 0; i < attributes.length; i++) {
+ int attribute = attributes[i];
+ String name = names[i];
+ if ( egl.eglGetConfigAttrib(display, config, attribute, value)) {
+ Log.w(TAG, String.format(" %s: %d\n", name, value[0]));
+ } else {
+ // Log.w(TAG, String.format(" %s: failed\n", name));
+ while (egl.eglGetError() != EGL10.EGL_SUCCESS);
+ }
+ }
+ }
+
+ // Subclasses can adjust these values:
+ protected int mRedSize;
+ protected int mGreenSize;
+ protected int mBlueSize;
+ protected int mAlphaSize;
+ protected int mDepthSize;
+ protected int mStencilSize;
+ private int[] mValue = new int[1];
+ }
+
+ private static class Renderer implements GLSurfaceView.Renderer {
+
+
+ public void onDrawFrame(GL10 gl) {
+ GodotLib.step();
+ }
+
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+
+ GodotLib.resize(width, height,!firsttime);
+ firsttime=false;
+ }
+
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ GodotLib.newcontext();
+ }
+ }
+}
diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp
new file mode 100644
index 0000000000..9c5003cb17
--- /dev/null
+++ b/platform/android/java_glue.cpp
@@ -0,0 +1,1153 @@
+/*************************************************************************/
+/* java_glue.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef ANDROID_NATIVE_ACTIVITY
+
+#include "java_glue.h"
+#include "os_android.h"
+#include "main/main.h"
+#include <unistd.h>
+#include "file_access_jandroid.h"
+#include "dir_access_jandroid.h"
+#include "audio_driver_jandroid.h"
+#include "globals.h"
+#include "thread_jandroid.h"
+#include "core/os/keyboard.h"
+static OS_Android *os_android=NULL;
+
+
+jvalue _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant* p_arg, bool force_jobject = false) {
+
+ jvalue v;
+
+ switch(p_type) {
+
+ case Variant::BOOL: {
+
+ if (force_jobject) {
+ jclass bclass = env->FindClass("java/lang/Boolean");
+ jmethodID ctor = env->GetMethodID(bclass, "<init>", "(Z)V");
+ jvalue val;
+ val.z = (bool)(*p_arg);
+ jobject obj = env->NewObjectA(bclass, ctor, &val);
+ v.l = obj;
+ } else {
+ v.z=*p_arg;
+ };
+ } break;
+ case Variant::INT: {
+
+ if (force_jobject) {
+
+ jclass bclass = env->FindClass("java/lang/Integer");
+ jmethodID ctor = env->GetMethodID(bclass, "<init>", "(I)V");
+ jvalue val;
+ val.i = (int)(*p_arg);
+ jobject obj = env->NewObjectA(bclass, ctor, &val);
+ v.l = obj;
+
+ } else {
+ v.i=*p_arg;
+ };
+ } break;
+ case Variant::REAL: {
+
+ if (force_jobject) {
+
+ jclass bclass = env->FindClass("java/lang/Double");
+ jmethodID ctor = env->GetMethodID(bclass, "<init>", "(D)V");
+ jvalue val;
+ val.d = (double)(*p_arg);
+ jobject obj = env->NewObjectA(bclass, ctor, &val);
+ v.l = obj;
+
+ } else {
+ v.f=*p_arg;
+ };
+ } break;
+ case Variant::STRING: {
+
+ String s = *p_arg;
+ jstring jStr = env->NewStringUTF(s.utf8().get_data());
+ v.l=jStr;
+ } break;
+ case Variant::STRING_ARRAY: {
+
+ DVector<String> sarray = *p_arg;
+ jobjectArray arr = env->NewObjectArray(sarray.size(),env->FindClass("java/lang/String"),env->NewStringUTF(""));
+
+ for(int j=0;j<sarray.size();j++) {
+
+ env->SetObjectArrayElement(arr,j,env->NewStringUTF( sarray[j].utf8().get_data() ));
+ }
+ v.l=arr;
+
+ } break;
+
+ case Variant::DICTIONARY: {
+
+ Dictionary dict = *p_arg;
+ jclass dclass = env->FindClass("com/android/godot/Dictionary");
+ jmethodID ctor = env->GetMethodID(dclass, "<init>", "()V");
+ jobject jdict = env->NewObject(dclass, ctor);
+
+ Array keys = dict.keys();
+
+ jobjectArray jkeys = env->NewObjectArray(keys.size(), env->FindClass("java/lang/String"), env->NewStringUTF(""));
+ for (int j=0; j<keys.size(); j++) {
+ env->SetObjectArrayElement(jkeys, j, env->NewStringUTF(String(keys[j]).utf8().get_data()));
+ };
+
+ jmethodID set_keys = env->GetMethodID(dclass, "set_keys", "([Ljava/lang/String;)V");
+ jvalue val;
+ val.l = jkeys;
+ env->CallVoidMethodA(jdict, set_keys, &val);
+
+ jobjectArray jvalues = env->NewObjectArray(keys.size(), env->FindClass("java/lang/Object"), NULL);
+
+ for (int j=0; j<keys.size(); j++) {
+ Variant var = dict[keys[j]];
+ val = _variant_to_jvalue(env, var.get_type(), &var, true);
+ env->SetObjectArrayElement(jvalues, j, val.l);
+ };
+
+ jmethodID set_values = env->GetMethodID(dclass, "set_values", "([Ljava/lang/Object;)V");
+ val.l = jvalues;
+ env->CallVoidMethodA(jdict, set_values, &val);
+
+ v.l = jdict;
+ } break;
+
+ case Variant::INT_ARRAY: {
+
+ DVector<int> array = *p_arg;
+ jintArray arr = env->NewIntArray(array.size());
+ DVector<int>::Read r = array.read();
+ env->SetIntArrayRegion(arr,0,array.size(),r.ptr());
+ v.l=arr;
+
+ } break;
+ case Variant::REAL_ARRAY: {
+
+ DVector<float> array = *p_arg;
+ jfloatArray arr = env->NewFloatArray(array.size());
+ DVector<float>::Read r = array.read();
+ env->SetFloatArrayRegion(arr,0,array.size(),r.ptr());
+ v.l=arr;
+
+ } break;
+ default: {
+
+ v.i = 0;
+ } break;
+
+ }
+ return v;
+};
+
+String _get_class_name(JNIEnv * env, jclass cls, bool* array) {
+
+ jclass cclass = env->FindClass("java/lang/Class");
+ jmethodID getName = env->GetMethodID(cclass, "getName", "()Ljava/lang/String;");
+ jstring clsName=(jstring) env->CallObjectMethod(cls, getName);
+
+ if (array) {
+ jmethodID isArray = env->GetMethodID(cclass, "isArray", "()Z");
+ jboolean isarr = env->CallBooleanMethod(cls, isArray);
+ (*array) = isarr ? true : false;
+ }
+
+ return env->GetStringUTFChars( clsName, NULL );
+};
+
+
+Variant _jobject_to_variant(JNIEnv * env, jobject obj) {
+
+ jclass c = env->GetObjectClass(obj);
+ bool array;
+ String name = _get_class_name(env, c, &array);
+ //print_line("name is " + name + ", array "+Variant(array));
+
+ if (name == "java.lang.String") {
+
+ return String::utf8(env->GetStringUTFChars( (jstring)obj, NULL ));
+ };
+
+
+ if (name == "[Ljava.lang.String;") {
+
+ jobjectArray arr = (jobjectArray)obj;
+ int stringCount = env->GetArrayLength(arr);
+ //print_line("String array! " + String::num(stringCount));
+ DVector<String> sarr;
+
+ for (int i=0; i<stringCount; i++) {
+ jstring string = (jstring) env->GetObjectArrayElement(arr, i);
+ const char *rawString = env->GetStringUTFChars(string, 0);
+ sarr.push_back(String(rawString));
+ }
+
+ return sarr;
+ };
+
+ if (name == "java.lang.Boolean") {
+
+ jmethodID boolValue = env->GetMethodID(c, "booleanValue", "()Z");
+ bool ret = env->CallBooleanMethod(obj, boolValue);
+ return ret;
+ };
+
+ if (name == "java.lang.Integer") {
+
+ jclass nclass = env->FindClass("java/lang/Number");
+ jmethodID intValue = env->GetMethodID(nclass, "intValue", "()I");
+ int ret = env->CallIntMethod(obj, intValue);
+ return ret;
+ };
+
+ if (name == "[I") {
+
+ jintArray arr = (jintArray)obj;
+ int fCount = env->GetArrayLength(arr);
+ DVector<int> sarr;
+ sarr.resize(fCount);
+
+ DVector<int>::Write w = sarr.write();
+ env->GetIntArrayRegion(arr,0,fCount,w.ptr());
+ w = DVector<int>::Write();
+ return sarr;
+ };
+
+ if (name == "java.lang.Float" || name == "java.lang.Double") {
+
+ jclass nclass = env->FindClass("java/lang/Number");
+ jmethodID doubleValue = env->GetMethodID(nclass, "doubleValue", "()D");
+ double ret = env->CallDoubleMethod(obj, doubleValue);
+ return ret;
+ };
+
+ if (name == "[D") {
+
+ jdoubleArray arr = (jdoubleArray)obj;
+ int fCount = env->GetArrayLength(arr);
+ RealArray sarr;
+ sarr.resize(fCount);
+
+ RealArray::Write w = sarr.write();
+
+ for (int i=0; i<fCount; i++) {
+
+ double n;
+ env->GetDoubleArrayRegion(arr, i, 1, &n);
+ w.ptr()[i] = n;
+
+ };
+ return sarr;
+ };
+
+ if (name == "[F") {
+
+ jfloatArray arr = (jfloatArray)obj;
+ int fCount = env->GetArrayLength(arr);
+ RealArray sarr;
+ sarr.resize(fCount);
+
+
+ RealArray::Write w = sarr.write();
+
+ for (int i=0; i<fCount; i++) {
+
+ float n;
+ env->GetFloatArrayRegion(arr, i, 1, &n);
+ w.ptr()[i] = n;
+
+ };
+ return sarr;
+ };
+
+
+ if (name == "[Ljava.lang.Object;") {
+
+ jobjectArray arr = (jobjectArray)obj;
+ int objCount = env->GetArrayLength(arr);
+ Array varr;
+
+ for (int i=0; i<objCount; i++) {
+ jobject jobj = env->GetObjectArrayElement(arr, i);
+ Variant v = _jobject_to_variant(env, jobj);
+ varr.push_back(v);
+ }
+
+ return varr;
+ };
+
+ if (name == "com.android.godot.Dictionary") {
+
+ Dictionary ret;
+ jclass oclass = c;
+ jmethodID get_keys = env->GetMethodID(oclass, "get_keys", "()[Ljava/lang/String;");
+ jobjectArray arr = (jobjectArray)env->CallObjectMethod(obj, get_keys);
+
+ StringArray keys = _jobject_to_variant(env, arr);
+
+ jmethodID get_values = env->GetMethodID(oclass, "get_values", "()[Ljava/lang/Object;");
+ arr = (jobjectArray)env->CallObjectMethod(obj, get_values);
+
+ Array vals = _jobject_to_variant(env, arr);
+
+ //print_line("adding " + String::num(keys.size()) + " to Dictionary!");
+ for (int i=0; i<keys.size(); i++) {
+
+ ret[keys[i]] = vals[i];
+ };
+
+ return ret;
+ };
+
+ return Variant();
+};
+
+class JNISingleton : public Object {
+
+ OBJ_TYPE( JNISingleton, Object );
+
+
+ struct MethodData {
+
+
+ jmethodID method;
+ Variant::Type ret_type;
+ Vector<Variant::Type> argtypes;
+ };
+
+ jobject instance;
+ Map<StringName,MethodData> method_map;
+
+public:
+
+ virtual Variant call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error) {
+
+ //print_line("attempt to call "+String(p_method));
+
+ r_error.error=Variant::CallError::CALL_OK;
+
+ Map<StringName,MethodData >::Element *E=method_map.find(p_method);
+ if (!E) {
+
+ print_line("no exists");
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ return Variant();
+ }
+
+
+ int ac = E->get().argtypes.size();
+ if (ac<p_argcount) {
+
+ print_line("fewargs");
+ r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument=ac;
+ return Variant();
+ }
+
+ if (ac>p_argcount) {
+
+ print_line("manyargs");
+ r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument=ac;
+ return Variant();
+ }
+
+
+
+ for(int i=0;i<p_argcount;i++) {
+
+ if (!Variant::can_convert(p_args[i]->get_type(),E->get().argtypes[i])) {
+
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=i;
+ r_error.expected=E->get().argtypes[i];
+ }
+ }
+
+
+ jvalue *v=NULL;
+
+ if (p_argcount) {
+
+ v=(jvalue*)alloca( sizeof(jvalue)*p_argcount );
+ }
+
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ //print_line("argcount "+String::num(p_argcount));
+ for(int i=0;i<p_argcount;i++) {
+
+ v[i] = _variant_to_jvalue(env, E->get().argtypes[i], p_args[i]);
+ }
+
+ //print_line("calling method!!");
+
+ Variant ret;
+
+ switch(E->get().ret_type) {
+
+ case Variant::NIL: {
+
+
+ //print_line("call void");
+ env->CallVoidMethodA(instance,E->get().method,v);
+ } break;
+ case Variant::BOOL: {
+
+ ret = env->CallBooleanMethodA(instance,E->get().method,v);
+ //print_line("call bool");
+ } break;
+ case Variant::INT: {
+
+ ret = env->CallIntMethodA(instance,E->get().method,v);
+ //print_line("call int");
+ } break;
+ case Variant::REAL: {
+
+ ret = env->CallFloatMethodA(instance,E->get().method,v);
+ } break;
+ case Variant::STRING: {
+
+ jobject o = env->CallObjectMethodA(instance,E->get().method,v);
+ String singname = env->GetStringUTFChars((jstring)o, NULL );
+ } break;
+ case Variant::STRING_ARRAY: {
+
+ jobjectArray arr = (jobjectArray)env->CallObjectMethodA(instance,E->get().method,v);
+
+ ret = _jobject_to_variant(env, arr);
+
+ } break;
+ case Variant::INT_ARRAY: {
+
+ jintArray arr = (jintArray)env->CallObjectMethodA(instance,E->get().method,v);
+
+ int fCount = env->GetArrayLength(arr);
+ DVector<int> sarr;
+ sarr.resize(fCount);
+
+ DVector<int>::Write w = sarr.write();
+ env->GetIntArrayRegion(arr,0,fCount,w.ptr());
+ w = DVector<int>::Write();
+ ret=sarr;
+ } break;
+ case Variant::REAL_ARRAY: {
+
+ jfloatArray arr = (jfloatArray)env->CallObjectMethodA(instance,E->get().method,v);
+
+ int fCount = env->GetArrayLength(arr);
+ DVector<float> sarr;
+ sarr.resize(fCount);
+
+ DVector<float>::Write w = sarr.write();
+ env->GetFloatArrayRegion(arr,0,fCount,w.ptr());
+ w = DVector<float>::Write();
+ ret=sarr;
+ } break;
+
+ case Variant::DICTIONARY: {
+
+ //print_line("call dictionary");
+ jobject obj = env->CallObjectMethodA(instance, E->get().method, v);
+ ret = _jobject_to_variant(env, obj);
+
+ } break;
+ default: {
+
+
+ print_line("failure..");
+ ERR_FAIL_V(Variant());
+ } break;
+ }
+
+ //print_line("success");
+
+ return ret;
+ }
+
+
+ jobject get_instance() const {
+
+ return instance;
+ }
+ void set_instance(jobject p_instance) {
+
+ instance=p_instance;
+ }
+
+
+ void add_method(const StringName& p_name, jmethodID p_method,const Vector<Variant::Type>& p_args, Variant::Type p_ret_type) {
+
+ MethodData md;
+ md.method=p_method;
+ md.argtypes=p_args;
+ md.ret_type=p_ret_type;
+ method_map[p_name]=md;
+
+ }
+
+
+ JNISingleton() {}
+
+};
+
+
+struct TST {
+
+ int a;
+ TST() {
+
+ a=5;
+ }
+};
+
+TST tst;
+
+struct JAndroidPointerEvent {
+
+ Vector<OS_Android::TouchPos> points;
+ int pointer;
+ int what;
+};
+
+static List<JAndroidPointerEvent> pointer_events;
+static List<InputEvent> key_events;
+static bool initialized=false;
+static Mutex *input_mutex=NULL;
+static Mutex *suspend_mutex=NULL;
+static int step=0;
+static bool resized=false;
+static bool resized_reload=false;
+static bool quit_request=false;
+static Size2 new_size;
+static Vector3 accelerometer;
+static HashMap<String,JNISingleton*> jni_singletons;
+static jobject godot_io;
+
+typedef void (*GFXInitFunc)(void *ud,bool gl2);
+
+static jmethodID _on_video_init=0;
+static jobject _godot_instance;
+
+static jmethodID _openURI=0;
+static jmethodID _getDataDir=0;
+static jmethodID _getLocale=0;
+static jmethodID _getModel=0;
+static jmethodID _showKeyboard=0;
+static jmethodID _hideKeyboard=0;
+static jmethodID _setScreenOrientation=0;
+static jmethodID _getUniqueID=0;
+
+
+static void _gfx_init_func(void* ud, bool gl2) {
+
+}
+
+
+static int _open_uri(const String& p_uri) {
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ jstring jStr = env->NewStringUTF(p_uri.utf8().get_data());
+ return env->CallIntMethod(godot_io,_openURI,jStr) ;
+}
+
+static String _get_data_dir() {
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ jstring s =(jstring)env->CallObjectMethod(godot_io,_getDataDir);
+ return String(env->GetStringUTFChars( s, NULL ));
+}
+
+static String _get_locale() {
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ jstring s =(jstring)env->CallObjectMethod(godot_io,_getLocale);
+ return String(env->GetStringUTFChars( s, NULL ));
+}
+
+static String _get_model() {
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ jstring s =(jstring)env->CallObjectMethod(godot_io,_getModel);
+ return String(env->GetStringUTFChars( s, NULL ));
+}
+
+static String _get_unique_id() {
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ jstring s =(jstring)env->CallObjectMethod(godot_io,_getUniqueID);
+ return String(env->GetStringUTFChars( s, NULL ));
+}
+
+static void _show_vk(const String& p_existing) {
+
+ JNIEnv* env = ThreadAndroid::get_env();
+ jstring jStr = env->NewStringUTF(p_existing.utf8().get_data());
+ env->CallVoidMethod(godot_io, _showKeyboard, jStr);
+};
+
+static void _set_screen_orient(int p_orient) {
+
+ JNIEnv* env = ThreadAndroid::get_env();
+ env->CallVoidMethod(godot_io, _setScreenOrientation, p_orient );
+};
+
+static void _hide_vk() {
+
+ JNIEnv* env = ThreadAndroid::get_env();
+ env->CallVoidMethod(godot_io, _hideKeyboard);
+};
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_initialize(JNIEnv * env, jobject obj, jobject activity,jboolean p_need_reload_hook) {
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","**INIT EVENT! - %p\n",env);
+
+
+ initialized=true;
+ _godot_instance=activity;
+
+ JavaVM *jvm;
+ env->GetJavaVM(&jvm);
+
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","***************** HELLO FROM JNI!!!!!!!!");
+
+ {
+ //setup IO Object
+
+ jclass cls = env->FindClass("com/android/godot/Godot");
+ if (cls) {
+
+ cls=(jclass)env->NewGlobalRef(cls);
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******CLASS FOUND!!!");
+ }
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP2, %p",cls);
+ jfieldID fid = env->GetStaticFieldID(cls, "io", "Lcom/android/godot/GodotIO;");
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP3 %i",fid);
+ jobject ob = env->GetStaticObjectField(cls,fid);
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP4, %p",ob);
+ jobject gob = env->NewGlobalRef(ob);
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP4.5, %p",gob);
+ godot_io=gob;
+
+ _on_video_init = env->GetMethodID(cls, "onVideoInit", "(Z)V");
+
+ jclass clsio = env->FindClass("com/android/godot/Godot");
+ if (cls) {
+ jclass c = env->GetObjectClass(gob);
+ _openURI = env->GetMethodID(c,"openURI","(Ljava/lang/String;)I");
+ _getDataDir = env->GetMethodID(c,"getDataDir","()Ljava/lang/String;");
+ _getLocale = env->GetMethodID(c,"getLocale","()Ljava/lang/String;");
+ _getModel = env->GetMethodID(c,"getModel","()Ljava/lang/String;");
+ _getUniqueID = env->GetMethodID(c,"getUniqueID","()Ljava/lang/String;");
+ _showKeyboard = env->GetMethodID(c,"showKeyboard","(Ljava/lang/String;)V");
+ _hideKeyboard = env->GetMethodID(c,"hideKeyboard","()V");
+ _setScreenOrientation = env->GetMethodID(c,"setScreenOrientation","(I)V");
+ }
+
+ ThreadAndroid::make_default(jvm);
+ FileAccessJAndroid::setup(gob);
+ DirAccessJAndroid::setup(gob);
+ AudioDriverAndroid::setup(gob);
+ }
+
+
+
+ os_android = new OS_Android(_gfx_init_func,env,_open_uri,_get_data_dir,_get_locale, _get_model,_show_vk, _hide_vk,_set_screen_orient,_get_unique_id);
+ os_android->set_need_reload_hooks(p_need_reload_hook);
+
+ char wd[500];
+ getcwd(wd,500);
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","test construction %i\n",tst.a);
+ __android_log_print(ANDROID_LOG_INFO,"godot","running from dir %s\n",wd);
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","**SETUP");
+
+
+#if 0
+ char *args[]={"-test","render",NULL};
+ __android_log_print(ANDROID_LOG_INFO,"godot","pre asdasd setup...");
+ Error err = Main::setup("apk",2,args,false);
+#else
+ Error err = Main::setup("apk",0,NULL,false);
+#endif
+
+ if (err!=OK) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*****UNABLE TO SETUP");
+
+ return; //should exit instead and print the error
+ }
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","*****SETUP OK");
+
+ //video driver is determined here, because once initialized, it cant be changed
+ String vd = Globals::get_singleton()->get("display/driver");
+
+
+ if (vd.to_upper()=="GLES1")
+ env->CallVoidMethod(_godot_instance, _on_video_init, (jboolean)false);
+ else
+ env->CallVoidMethod(_godot_instance, _on_video_init, (jboolean)true);
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","**START");
+
+ input_mutex=Mutex::create();
+ suspend_mutex=Mutex::create();
+
+
+}
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_resize(JNIEnv * env, jobject obj, jint width, jint height, jboolean reload) {
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","^_^_^_^_^ resize %lld, %i, %i\n",Thread::get_caller_ID(),width,height);
+ if (os_android)
+ os_android->set_display_size(Size2(width,height));
+
+ /*input_mutex->lock();
+ resized=true;
+ if (reload)
+ resized_reload=true;
+ new_size=Size2(width,height);
+ input_mutex->unlock();*/
+
+}
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_newcontext(JNIEnv * env, jobject obj) {
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","^_^_^_^_^ newcontext %lld\n",Thread::get_caller_ID());
+ if (os_android && step > 0) {
+
+ os_android->reload_gfx();
+ }
+
+}
+
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_quit(JNIEnv * env, jobject obj) {
+
+ input_mutex->lock();
+ quit_request=true;
+ input_mutex->unlock();
+
+}
+
+static void _initialize_java_modules() {
+
+
+ String modules = Globals::get_singleton()->get("android/modules");
+ Vector<String> mods = modules.split(",",false);
+ __android_log_print(ANDROID_LOG_INFO,"godot","mod count: %i",mods.size());
+
+ if (mods.size()) {
+
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ jclass activityClass = env->FindClass("com/android/godot/Godot");
+
+ jmethodID getClassLoader = env->GetMethodID(activityClass,"getClassLoader", "()Ljava/lang/ClassLoader;");
+
+ jobject cls = env->CallObjectMethod(_godot_instance, getClassLoader);
+
+ jclass classLoader = env->FindClass("java/lang/ClassLoader");
+
+ jmethodID findClass = env->GetMethodID(classLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
+
+ for (int i=0;i<mods.size();i++) {
+
+ String m = mods[i];
+ //jclass singletonClass = env->FindClass(m.utf8().get_data());
+
+ print_line("LOADING MODULE: "+m);
+ jstring strClassName = env->NewStringUTF(m.utf8().get_data());
+ jclass singletonClass = (jclass)env->CallObjectMethod(cls, findClass, strClassName);
+
+ if (!singletonClass) {
+
+ ERR_EXPLAIN("Couldn't find singleton for class: "+m);
+ ERR_CONTINUE(!singletonClass);
+ }
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","****^*^*?^*^*class data %x",singletonClass);
+ jmethodID initialize = env->GetStaticMethodID(singletonClass, "initialize", "(Landroid/app/Activity;)Lcom/android/godot/Godot$SingletonBase;");
+
+ jobject obj = env->CallStaticObjectMethod(singletonClass,initialize,_godot_instance);
+ __android_log_print(ANDROID_LOG_INFO,"godot","****^*^*?^*^*class instance %x",obj);
+ jobject gob = env->NewGlobalRef(obj);
+
+
+ }
+
+ }
+
+}
+
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_step(JNIEnv * env, jobject obj)
+{
+
+
+ ThreadAndroid::setup_thread();
+
+ //__android_log_print(ANDROID_LOG_INFO,"godot","**STEP EVENT! - %p-%i\n",env,Thread::get_caller_ID());
+
+
+ suspend_mutex->lock();
+ input_mutex->lock();
+ //first time step happens, initialize
+ if (step == 0) {
+ // ugly hack to initialize the rest of the engine
+ // because of the way android forces you to do everything with threads
+
+ _initialize_java_modules();
+
+ Main::setup2();
+ ++step;
+ suspend_mutex->unlock();
+ input_mutex->unlock();
+ return;
+ };
+ if (step == 1) {
+ if (!Main::start()) {
+
+ input_mutex->unlock();
+ suspend_mutex->lock();
+ return; //should exit instead and print the error
+ }
+
+ os_android->main_loop_begin();
+ ++step;
+ }
+
+ while(pointer_events.size()) {
+
+ JAndroidPointerEvent jpe=pointer_events.front()->get();
+ os_android->process_touch(jpe.what,jpe.pointer,jpe.points);
+
+ pointer_events.pop_front();
+ }
+
+ while (key_events.size()) {
+
+ InputEvent event = key_events.front()->get();
+ os_android->process_event(event);
+
+ key_events.pop_front();
+ };
+
+ if (quit_request) {
+
+ os_android->main_loop_request_quit();
+ quit_request=false;
+ }
+
+
+ input_mutex->unlock();
+
+ os_android->process_accelerometer(accelerometer);
+
+ if (os_android->main_loop_iterate()==true) {
+
+ jclass cls = env->FindClass("com/android/godot/Godot");
+ jmethodID _finish = env->GetMethodID(cls, "forceQuit", "()V");
+ env->CallVoidMethod(_godot_instance, _finish);
+ __android_log_print(ANDROID_LOG_INFO,"godot","**FINISH REQUEST!!! - %p-%i\n",env,Thread::get_caller_ID());
+
+ }
+
+ suspend_mutex->unlock();
+
+}
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_touch(JNIEnv * env, jobject obj, jint ev,jint pointer, jint count, jintArray positions) {
+
+
+
+ //__android_log_print(ANDROID_LOG_INFO,"godot","**TOUCH EVENT! - %p-%i\n",env,Thread::get_caller_ID());
+
+
+ Vector<OS_Android::TouchPos> points;
+ for(int i=0;i<count;i++) {
+
+ jint p[3];
+ env->GetIntArrayRegion(positions,i*3,3,p);
+ OS_Android::TouchPos tp;
+ tp.pos=Point2(p[1],p[2]);
+ tp.id=p[0];
+ points.push_back(tp);
+ }
+
+ JAndroidPointerEvent jpe;
+ jpe.pointer=pointer;
+ jpe.points=points;
+ jpe.what=ev;
+
+ input_mutex->lock();
+
+ pointer_events.push_back(jpe);
+
+ input_mutex->unlock();
+ //if (os_android)
+// os_android->process_touch(ev,pointer,points);
+
+}
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_key(JNIEnv * env, jobject obj, jint ev, jint p_unicode_char, jboolean p_pressed) {
+
+ InputEvent ievent;
+ ievent.type = InputEvent::KEY;
+ ievent.device = 0;
+ int val = p_unicode_char;
+ ievent.key.scancode = val;
+ ievent.key.unicode = val;
+ if (val == 61448) {
+ ievent.key.scancode = KEY_BACKSPACE;
+ ievent.key.unicode = KEY_BACKSPACE;
+ };
+ if (val == 61453) {
+ ievent.key.scancode = KEY_ENTER;
+ ievent.key.unicode = KEY_ENTER;
+ };
+
+ input_mutex->lock();
+ key_events.push_back(ievent);
+ input_mutex->unlock();
+};
+
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_accelerometer(JNIEnv * env, jobject obj, jfloat x, jfloat y, jfloat z) {
+
+ input_mutex->lock();
+ accelerometer=Vector3(x,y,z);
+ input_mutex->unlock();
+
+}
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_focusin(JNIEnv * env, jobject obj){
+
+ if (!suspend_mutex)
+ return;
+ suspend_mutex->lock();
+
+ if (os_android && step > 0)
+ os_android->main_loop_focusin();
+
+ suspend_mutex->unlock();
+}
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_focusout(JNIEnv * env, jobject obj){
+
+ if (!suspend_mutex)
+ return;
+ suspend_mutex->lock();
+
+ if (os_android && step > 0)
+ os_android->main_loop_focusout();
+
+ suspend_mutex->unlock();
+
+}
+
+
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_audio(JNIEnv * env, jobject obj) {
+
+ ThreadAndroid::setup_thread();
+ AudioDriverAndroid::thread_func(env);
+
+
+}
+
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_singleton(JNIEnv * env, jobject obj, jstring name,jobject p_object){
+
+ String singname = env->GetStringUTFChars( name, NULL );
+ JNISingleton *s = memnew( JNISingleton );
+ s->set_instance(env->NewGlobalRef(p_object));
+ jni_singletons[singname]=s;
+
+ Globals::get_singleton()->add_singleton(Globals::Singleton(singname,s));
+ Globals::get_singleton()->set(singname,s);
+
+}
+
+
+static Variant::Type get_jni_type(const String& p_type) {
+
+ static struct {
+ const char *name;
+ Variant::Type type;
+ } _type_to_vtype[]={
+ {"void",Variant::NIL},
+ {"boolean",Variant::BOOL},
+ {"int",Variant::INT},
+ {"float",Variant::REAL},
+ {"double", Variant::REAL},
+ {"java.lang.String",Variant::STRING},
+ {"[I",Variant::INT_ARRAY},
+ {"[F",Variant::REAL_ARRAY},
+ {"[java.lang.String",Variant::STRING_ARRAY},
+ {"com.android.godot.Dictionary", Variant::DICTIONARY},
+ {NULL,Variant::NIL}
+ };
+
+ int idx=0;
+
+ while (_type_to_vtype[idx].name) {
+
+ if (p_type==_type_to_vtype[idx].name)
+ return _type_to_vtype[idx].type;
+
+ idx++;
+ }
+
+ return Variant::NIL;
+}
+
+
+static const char* get_jni_sig(const String& p_type) {
+
+ print_line("getting sig for " + p_type);
+ static struct {
+ const char *name;
+ const char *sig;
+ } _type_to_vtype[]={
+ {"void","V"},
+ {"boolean","Z"},
+ {"int","I"},
+ {"float","F"},
+ {"double","D"},
+ {"java.lang.String","Ljava/lang/String;"},
+ {"com.android.godot.Dictionary", "Lcom/android/godot/Dictionary;"},
+ {"[I","[I"},
+ {"[F","[F"},
+ {"[java.lang.String","[Ljava/lang/String;"},
+ {NULL,"V"}
+ };
+
+ int idx=0;
+
+ while (_type_to_vtype[idx].name) {
+
+ if (p_type==_type_to_vtype[idx].name)
+ return _type_to_vtype[idx].sig;
+
+ idx++;
+ }
+
+
+ return "Ljava/lang/Object;";
+}
+
+JNIEXPORT jstring JNICALL Java_com_android_godot_GodotLib_getGlobal(JNIEnv * env, jobject obj, jstring path) {
+
+ String js = env->GetStringUTFChars( path, NULL );
+
+ return env->NewStringUTF(Globals::get_singleton()->get(js).operator String().utf8().get_data());
+
+
+}
+
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_method(JNIEnv * env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args){
+
+ String singname = env->GetStringUTFChars( sname, NULL );
+
+ ERR_FAIL_COND(!jni_singletons.has(singname));
+
+ JNISingleton *s = jni_singletons.get(singname);
+
+
+ String mname = env->GetStringUTFChars( name, NULL );
+ String retval = env->GetStringUTFChars( ret, NULL );
+ Vector<Variant::Type> types;
+ String cs="(";
+
+
+ int stringCount = env->GetArrayLength(args);
+
+ print_line("Singl: "+singname+" Method: "+mname+" RetVal: "+retval);
+ for (int i=0; i<stringCount; i++) {
+
+ jstring string = (jstring) env->GetObjectArrayElement(args, i);
+ const char *rawString = env->GetStringUTFChars(string, 0);
+ types.push_back(get_jni_type(String(rawString)));
+ cs+=get_jni_sig(String(rawString));
+ }
+
+ cs+=")";
+ cs+=get_jni_sig(retval);
+ jclass cls = env->GetObjectClass(s->get_instance());
+ print_line("METHOD: "+mname+" sig: "+cs);
+ jmethodID mid = env->GetMethodID(cls, mname.ascii().get_data(), cs.ascii().get_data());
+ if (!mid) {
+
+ print_line("FAILED GETTING METHOID "+mname);
+ }
+
+ s->add_method(mname,mid,types,get_jni_type(retval));
+
+
+}
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_callobject(JNIEnv * env, jobject p_obj, jint ID, jstring method, jobjectArray params) {
+
+ String str_method = env->GetStringUTFChars( method, NULL );
+
+ Object* obj = ObjectDB::get_instance(ID);
+ ERR_FAIL_COND(!obj);
+
+ int count = env->GetArrayLength(params);
+ Variant* vlist = (Variant*)alloca(sizeof(Variant) * count);
+ Variant** vptr = (Variant**)alloca(sizeof(Variant*) * count);
+ for (int i=0; i<count; i++) {
+
+ jobject obj = env->GetObjectArrayElement(params, i);
+ Variant v = _jobject_to_variant(env, obj);
+ memnew_placement(&vlist[i], Variant);
+ vlist[i] = v;
+ vptr[i] = &vlist[i];
+ };
+
+ Variant::CallError err;
+ obj->call(str_method, (const Variant**)vptr, count, err);
+ // something
+};
+
+
+//Main::cleanup();
+
+//return os.get_exit_code();
+#endif
diff --git a/platform/android/java_glue.h b/platform/android/java_glue.h
new file mode 100644
index 0000000000..7a0666f63d
--- /dev/null
+++ b/platform/android/java_glue.h
@@ -0,0 +1,58 @@
+/*************************************************************************/
+/* java_glue.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef ANDROID_NATIVE_ACTIVITY
+
+#ifndef JAVA_GLUE_H
+#define JAVA_GLUE_H
+
+#include <jni.h>
+#include <android/log.h>
+
+
+extern "C" {
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_initialize(JNIEnv * env, jobject obj, jobject activity,jboolean p_need_reload_hook);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_resize(JNIEnv * env, jobject obj, jint width, jint height, jboolean reload);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_newcontext(JNIEnv * env, jobject obj);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_step(JNIEnv * env, jobject obj);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_quit(JNIEnv * env, jobject obj);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_touch(JNIEnv * env, jobject obj, jint ev,jint pointer, jint count, jintArray positions);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_key(JNIEnv * env, jobject obj, jint ev, jint p_unicode_char, jboolean p_pressed);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_audio(JNIEnv * env, jobject obj);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_accelerometer(JNIEnv * env, jobject obj, jfloat x, jfloat y, jfloat z);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_focusin(JNIEnv * env, jobject obj);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_focusout(JNIEnv * env, jobject obj);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_singleton(JNIEnv * env, jobject obj, jstring name,jobject p_object);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_method(JNIEnv * env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args);
+ JNIEXPORT jstring JNICALL Java_com_android_godot_GodotLib_getGlobal(JNIEnv * env, jobject obj, jstring path);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_callobject(JNIEnv * env, jobject obj, jint ID, jstring method, jobjectArray params);
+};
+
+
+#endif
+#endif // JAVA_GLUE_H
diff --git a/platform/android/logo.png b/platform/android/logo.png
new file mode 100644
index 0000000000..a7e2c6f130
--- /dev/null
+++ b/platform/android/logo.png
Binary files differ
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
new file mode 100644
index 0000000000..9d9da3750e
--- /dev/null
+++ b/platform/android/os_android.cpp
@@ -0,0 +1,709 @@
+/*************************************************************************/
+/* os_android.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "os_android.h"
+#include "drivers/gles2/rasterizer_gles2.h"
+#include "drivers/gles1/rasterizer_gles1.h"
+#include "core/io/file_access_buffered_fa.h"
+#include "drivers/unix/file_access_unix.h"
+#include "drivers/unix/dir_access_unix.h"
+
+#include "servers/visual/visual_server_raster.h"
+
+#include "main/main.h"
+
+#include "core/globals.h"
+
+#ifdef ANDROID_NATIVE_ACTIVITY
+#include "file_access_android.h"
+#include "dir_access_android.h"
+#else
+#include "file_access_jandroid.h"
+#include "dir_access_jandroid.h"
+#endif
+
+int OS_Android::get_video_driver_count() const {
+
+ return 2;
+}
+const char * OS_Android::get_video_driver_name(int p_driver) const {
+
+ return p_driver==0?"GLES2":"GLES1";
+}
+
+OS::VideoMode OS_Android::get_default_video_mode() const {
+
+ return OS::VideoMode();
+}
+
+int OS_Android::get_audio_driver_count() const {
+
+ return 1;
+}
+
+const char * OS_Android::get_audio_driver_name(int p_driver) const {
+
+ return "Android";
+}
+
+void OS_Android::initialize_core() {
+
+ OS_Unix::initialize_core();
+
+#ifdef ANDROID_NATIVE_ACTIVITY
+
+ FileAccess::make_default<FileAccessAndroid>(FileAccess::ACCESS_RESOURCES);
+ FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_USERDATA);
+ FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_FILESYSTEM);
+ //FileAccessBufferedFA<FileAccessUnix>::make_default();
+ DirAccess::make_default<DirAccessAndroid>(DirAccess::ACCESS_RESOURCES);
+ DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_USERDATA);
+ DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_FILESYSTEM);
+
+#else
+
+ FileAccess::make_default<FileAccessBufferedFA<FileAccessJAndroid> >(FileAccess::ACCESS_RESOURCES);
+ FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_USERDATA);
+ FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_FILESYSTEM);
+ //FileAccessBufferedFA<FileAccessUnix>::make_default();
+ DirAccess::make_default<DirAccessJAndroid>(DirAccess::ACCESS_RESOURCES);
+ DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_USERDATA);
+ DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_FILESYSTEM);
+
+#endif
+
+}
+
+void OS_Android::set_opengl_extensions(const char* p_gl_extensions) {
+
+ ERR_FAIL_COND(!p_gl_extensions);
+ gl_extensions=p_gl_extensions;
+}
+
+void OS_Android::initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver) {
+
+
+ use_gl2=p_video_driver!=1;
+
+
+ if (gfx_init_func)
+ gfx_init_func(gfx_init_ud,use_gl2);
+
+ AudioDriverManagerSW::add_driver(&audio_driver_android);
+
+
+ if (use_gl2) {
+ RasterizerGLES2 *rasterizer_gles22=memnew( RasterizerGLES2(false,use_reload_hooks,false,use_reload_hooks ) );
+ if (gl_extensions)
+ rasterizer_gles22->set_extensions(gl_extensions);
+ rasterizer = rasterizer_gles22;
+ } else {
+ rasterizer = memnew( RasterizerGLES1(use_reload_hooks, use_reload_hooks) );
+
+ }
+
+ visual_server = memnew( VisualServerRaster(rasterizer) );
+ visual_server->init();
+ visual_server->cursor_set_visible(false, 0);
+
+ AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton();
+
+ if (AudioDriverManagerSW::get_driver(p_audio_driver)->init()!=OK) {
+
+ ERR_PRINT("Initializing audio failed.");
+ }
+
+ sample_manager = memnew( SampleManagerMallocSW );
+ audio_server = memnew( AudioServerSW(sample_manager) );
+
+ audio_server->set_mixer_params(AudioMixerSW::INTERPOLATION_LINEAR,false);
+ audio_server->init();
+
+ spatial_sound_server = memnew( SpatialSoundServerSW );
+ spatial_sound_server->init();
+
+ spatial_sound_2d_server = memnew( SpatialSound2DServerSW );
+ spatial_sound_2d_server->init();
+
+ //
+ physics_server = memnew( PhysicsServerSW );
+ physics_server->init();
+ physics_2d_server = memnew( Physics2DServerSW );
+ physics_2d_server->init();
+
+ input = memnew( InputDefault );
+
+}
+
+void OS_Android::set_main_loop( MainLoop * p_main_loop ) {
+
+ main_loop=p_main_loop;
+ input->set_main_loop(p_main_loop);
+#if 0
+
+ print_line("preGS");
+ FileAccess *f=memnew( FileAccessAndroid );
+ print("made f %p\n",f);
+ Error err = f->open("AndroidManifest.xml",FileAccess::READ);
+ if (err) {
+
+ print("************NO FILE!!\n");
+ } else {
+ print("************YES FILE!!\n");
+ }
+ f->close();
+ print_line("end");
+
+
+ AAssetDir* aad = AAssetManager_openDir(FileAccessAndroid::asset_manager,".");
+
+ if (aad) {
+
+ print_line("DIR OPEN OK");
+
+ const char *fn= AAssetDir_getNextFileName(aad);
+
+ while(fn) {
+
+ print_line("FNAME: "+String(fn));
+ fn= AAssetDir_getNextFileName(aad);
+ }
+
+ AAssetDir_close(aad);
+ } else {
+
+ print_line("DIR NO OPEN");
+ }
+
+#endif
+
+}
+
+void OS_Android::delete_main_loop() {
+
+ memdelete( main_loop );
+}
+
+void OS_Android::finalize() {
+
+ memdelete(input);
+}
+
+
+void OS_Android::vprint(const char* p_format, va_list p_list, bool p_stderr) {
+
+ __android_log_vprint(p_stderr?ANDROID_LOG_ERROR:ANDROID_LOG_INFO,"godot",p_format,p_list);
+}
+
+void OS_Android::print(const char *p_format, ... ) {
+
+ va_list argp;
+ va_start(argp, p_format);
+ __android_log_vprint(ANDROID_LOG_INFO,"godot",p_format,argp);
+ va_end(argp);
+
+}
+
+void OS_Android::alert(const String& p_alert) {
+
+ print("ALERT: %s\n",p_alert.utf8().get_data());
+}
+
+
+void OS_Android::set_mouse_show(bool p_show) {
+
+ //android has no mouse...
+}
+
+void OS_Android::set_mouse_grab(bool p_grab) {
+
+ //it really has no mouse...!
+}
+
+bool OS_Android::is_mouse_grab_enabled() const {
+
+ //*sigh* technology has evolved so much since i was a kid..
+ return false;
+}
+Point2 OS_Android::get_mouse_pos() const {
+
+ return Point2();
+}
+int OS_Android::get_mouse_button_state() const {
+
+ return 0;
+}
+void OS_Android::set_window_title(const String& p_title) {
+
+
+}
+
+//interesting byt not yet
+//void set_clipboard(const String& p_text);
+//String get_clipboard() const;
+
+void OS_Android::set_video_mode(const VideoMode& p_video_mode,int p_screen) {
+
+
+}
+
+OS::VideoMode OS_Android::get_video_mode(int p_screen) const {
+
+ return default_videomode;
+}
+void OS_Android::get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen) const {
+
+ p_list->push_back(default_videomode);
+}
+
+String OS_Android::get_name() {
+
+ return "Android";
+}
+
+MainLoop *OS_Android::get_main_loop() const {
+
+ return main_loop;
+}
+
+bool OS_Android::can_draw() const {
+
+ return true; //always?
+}
+
+void OS_Android::set_cursor_shape(CursorShape p_shape) {
+
+ //android really really really has no mouse.. how amazing..
+}
+
+void OS_Android::main_loop_begin() {
+
+ if (main_loop)
+ main_loop->init();
+}
+bool OS_Android::main_loop_iterate() {
+
+ if (!main_loop)
+ return false;
+ return Main::iteration();
+}
+
+void OS_Android::main_loop_end() {
+
+ if (main_loop)
+ main_loop->finish();
+
+}
+
+void OS_Android::main_loop_focusout() {
+
+ if (main_loop)
+ main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
+ audio_driver_android.set_pause(true);
+
+}
+
+void OS_Android::main_loop_focusin(){
+
+ if (main_loop)
+ main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
+ audio_driver_android.set_pause(false);
+
+}
+
+
+void OS_Android::process_event(InputEvent p_event) {
+
+ p_event.ID = last_id++;
+ input->parse_input_event(p_event);
+};
+
+
+void OS_Android::process_touch(int p_what,int p_pointer, const Vector<TouchPos>& p_points) {
+
+// print_line("ev: "+itos(p_what)+" pnt: "+itos(p_pointer)+" pointc: "+itos(p_points.size()));
+
+ switch(p_what) {
+ case 0: { //gesture begin
+
+ if (touch.size()) {
+ //end all if exist
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_BUTTON;
+ ev.ID=last_id++;
+ ev.mouse_button.button_index=BUTTON_LEFT;
+ ev.mouse_button.button_mask=BUTTON_MASK_LEFT;
+ ev.mouse_button.pressed=false;
+ ev.mouse_button.x=touch[0].pos.x;
+ ev.mouse_button.y=touch[0].pos.y;
+ ev.mouse_button.global_x=touch[0].pos.x;
+ ev.mouse_button.global_y=touch[0].pos.y;
+ input->parse_input_event(ev);
+
+
+ for(int i=0;i<touch.size();i++) {
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_TOUCH;
+ ev.ID=last_id++;
+ ev.screen_touch.index=touch[i].id;
+ ev.screen_touch.pressed=false;
+ ev.screen_touch.x=touch[i].pos.x;
+ ev.screen_touch.y=touch[i].pos.y;
+ input->parse_input_event(ev);
+
+ }
+ }
+
+ touch.resize(p_points.size());
+ for(int i=0;i<p_points.size();i++) {
+ touch[i].id=p_points[i].id;
+ touch[i].pos=p_points[i].pos;
+ }
+
+ {
+ //send mouse
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_BUTTON;
+ ev.ID=last_id++;
+ ev.mouse_button.button_index=BUTTON_LEFT;
+ ev.mouse_button.button_mask=BUTTON_MASK_LEFT;
+ ev.mouse_button.pressed=true;
+ ev.mouse_button.x=touch[0].pos.x;
+ ev.mouse_button.y=touch[0].pos.y;
+ ev.mouse_button.global_x=touch[0].pos.x;
+ ev.mouse_button.global_y=touch[0].pos.y;
+ last_mouse=touch[0].pos;
+ input->parse_input_event(ev);
+ }
+
+
+ //send touch
+ for(int i=0;i<touch.size();i++) {
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_TOUCH;
+ ev.ID=last_id++;
+ ev.screen_touch.index=touch[i].id;
+ ev.screen_touch.pressed=true;
+ ev.screen_touch.x=touch[i].pos.x;
+ ev.screen_touch.y=touch[i].pos.y;
+ input->parse_input_event(ev);
+ }
+
+ } break;
+ case 1: { //motion
+
+
+ if (p_points.size()) {
+ //send mouse, should look for point 0?
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_MOTION;
+ ev.ID=last_id++;
+ ev.mouse_motion.button_mask=BUTTON_MASK_LEFT;
+ ev.mouse_motion.x=p_points[0].pos.x;
+ ev.mouse_motion.y=p_points[0].pos.y;
+ input->set_mouse_pos(Point2(ev.mouse_motion.x,ev.mouse_motion.y));
+ ev.mouse_motion.speed_x=input->get_mouse_speed().x;
+ ev.mouse_motion.speed_y=input->get_mouse_speed().y;
+ ev.mouse_motion.relative_x=p_points[0].pos.x-last_mouse.x;
+ ev.mouse_motion.relative_y=p_points[0].pos.y-last_mouse.y;
+ last_mouse=p_points[0].pos;
+ input->parse_input_event(ev);
+ }
+
+ ERR_FAIL_COND(touch.size()!=p_points.size());
+
+ for(int i=0;i<touch.size();i++) {
+
+ int idx=-1;
+ for(int j=0;j<p_points.size();j++) {
+
+ if (touch[i].id==p_points[j].id) {
+ idx=j;
+ break;
+ }
+
+ }
+
+ ERR_CONTINUE(idx==-1);
+
+ if (touch[i].pos==p_points[idx].pos)
+ continue; //no move unncesearily
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_DRAG;
+ ev.ID=last_id++;
+ ev.screen_drag.index=touch[i].id;
+ ev.screen_drag.x=p_points[idx].pos.x;
+ ev.screen_drag.y=p_points[idx].pos.y;
+ ev.screen_drag.relative_x=p_points[idx].pos.x - touch[i].pos.x;
+ ev.screen_drag.relative_y=p_points[idx].pos.y - touch[i].pos.y;
+ input->parse_input_event(ev);
+ touch[i].pos=p_points[idx].pos;
+ }
+
+
+ } break;
+ case 2: { //release
+
+
+
+ if (touch.size()) {
+ //end all if exist
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_BUTTON;
+ ev.ID=last_id++;
+ ev.mouse_button.button_index=BUTTON_LEFT;
+ ev.mouse_button.button_mask=BUTTON_MASK_LEFT;
+ ev.mouse_button.pressed=false;
+ ev.mouse_button.x=touch[0].pos.x;
+ ev.mouse_button.y=touch[0].pos.y;
+ ev.mouse_button.global_x=touch[0].pos.x;
+ ev.mouse_button.global_y=touch[0].pos.y;
+ input->parse_input_event(ev);
+
+
+ for(int i=0;i<touch.size();i++) {
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_TOUCH;
+ ev.ID=last_id++;
+ ev.screen_touch.index=touch[i].id;
+ ev.screen_touch.pressed=false;
+ ev.screen_touch.x=touch[i].pos.x;
+ ev.screen_touch.y=touch[i].pos.y;
+ input->parse_input_event(ev);
+
+ }
+ touch.clear();
+ }
+
+ } break;
+ case 3: { // add tuchi
+
+
+
+
+
+ ERR_FAIL_INDEX(p_pointer,p_points.size());
+
+ TouchPos tp=p_points[p_pointer];
+ touch.push_back(tp);
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_TOUCH;
+ ev.ID=last_id++;
+ ev.screen_touch.index=tp.id;
+ ev.screen_touch.pressed=true;
+ ev.screen_touch.x=tp.pos.x;
+ ev.screen_touch.y=tp.pos.y;
+ input->parse_input_event(ev);
+
+ } break;
+ case 4: {
+
+
+ for(int i=0;i<touch.size();i++) {
+ if (touch[i].id==p_pointer) {
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_TOUCH;
+ ev.ID=last_id++;
+ ev.screen_touch.index=touch[i].id;
+ ev.screen_touch.pressed=false;
+ ev.screen_touch.x=touch[i].pos.x;
+ ev.screen_touch.y=touch[i].pos.y;
+ input->parse_input_event(ev);
+ touch.remove(i);
+ i--;
+ }
+ }
+
+ } break;
+
+ }
+
+}
+
+void OS_Android::process_accelerometer(const Vector3& p_accelerometer) {
+
+ input->set_accelerometer(p_accelerometer);
+}
+
+bool OS_Android::has_touchscreen_ui_hint() const {
+
+ return true;
+}
+
+bool OS_Android::has_virtual_keyboard() const {
+
+ return true;
+};
+
+void OS_Android::show_virtual_keyboard(const String& p_existing_text,const Rect2& p_screen_rect) {
+
+ if (show_virtual_keyboard_func) {
+ show_virtual_keyboard_func(p_existing_text);
+ } else {
+
+ ERR_PRINT("Virtual keyboard not available");
+ };
+};
+
+void OS_Android::hide_virtual_keyboard() {
+
+ if (hide_virtual_keyboard_func) {
+
+ hide_virtual_keyboard_func();
+ } else {
+
+ ERR_PRINT("Virtual keyboard not available");
+ };
+};
+
+
+void OS_Android::init_video_mode(int p_video_width,int p_video_height) {
+
+ default_videomode.width=p_video_width;
+ default_videomode.height=p_video_height;
+ default_videomode.fullscreen=true;
+ default_videomode.resizable=false;
+}
+
+void OS_Android::main_loop_request_quit() {
+
+ if (main_loop)
+ main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST);
+}
+
+void OS_Android::set_display_size(Size2 p_size) {
+
+ default_videomode.width=p_size.x;
+ default_videomode.height=p_size.y;
+}
+
+void OS_Android::reload_gfx() {
+
+ if (gfx_init_func)
+ gfx_init_func(gfx_init_ud,use_gl2);
+ if (rasterizer)
+ rasterizer->reload_vram();
+}
+
+Error OS_Android::shell_open(String p_uri) {
+
+ if (open_uri_func)
+ return open_uri_func(p_uri)?ERR_CANT_OPEN:OK;
+ return ERR_UNAVAILABLE;
+};
+
+String OS_Android::get_resource_dir() const {
+
+ return "/"; //android has it's own filesystem for resources inside the APK
+}
+
+String OS_Android::get_locale() const {
+
+ if (get_locale_func)
+ return get_locale_func();
+ return OS_Unix::get_locale();
+}
+
+String OS_Android::get_model_name() const {
+
+ if (get_model_func)
+ return get_model_func();
+ return OS_Unix::get_model_name();
+}
+
+
+void OS_Android::set_need_reload_hooks(bool p_needs_them) {
+
+ use_reload_hooks=p_needs_them;
+}
+
+String OS_Android::get_data_dir() const {
+
+ if (get_data_dir_func)
+ return get_data_dir_func();
+ return ".";
+ //return Globals::get_singleton()->get_singleton_object("GodotOS")->call("get_data_dir");
+};
+
+
+void OS_Android::set_screen_orientation(ScreenOrientation p_orientation) {
+
+
+ if (set_screen_orientation_func)
+ set_screen_orientation_func(p_orientation);
+}
+
+
+String OS_Android::get_unique_ID() const {
+
+ if (get_unique_id_func)
+ return get_unique_id_func();
+ return OS::get_unique_ID();
+}
+
+
+OS_Android::OS_Android(GFXInitFunc p_gfx_init_func,void*p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetDataDirFunc p_get_data_dir_func,GetLocaleFunc p_get_locale_func,GetModelFunc p_get_model_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, SetScreenOrientationFunc p_screen_orient,GetUniqueIDFunc p_get_unique_id) {
+
+
+ default_videomode.width=800;
+ default_videomode.height=600;
+ default_videomode.fullscreen=true;
+ default_videomode.resizable=false;
+
+ gfx_init_func=p_gfx_init_func;
+ gfx_init_ud=p_gfx_init_ud;
+ main_loop=NULL;
+ last_id=1;
+ gl_extensions=NULL;
+ rasterizer=NULL;
+ use_gl2=false;
+
+ open_uri_func=p_open_uri_func;
+ get_data_dir_func=p_get_data_dir_func;
+ get_locale_func=p_get_locale_func;
+ get_model_func=p_get_model_func;
+ get_unique_id_func=p_get_unique_id;
+
+ show_virtual_keyboard_func = p_show_vk;
+ hide_virtual_keyboard_func = p_hide_vk;
+
+ set_screen_orientation_func=p_screen_orient;
+ use_reload_hooks=false;
+
+}
+
+OS_Android::~OS_Android() {
+
+
+}
diff --git a/platform/android/os_android.h b/platform/android/os_android.h
new file mode 100644
index 0000000000..93c672927e
--- /dev/null
+++ b/platform/android/os_android.h
@@ -0,0 +1,197 @@
+/*************************************************************************/
+/* os_android.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef OS_ANDROID_H
+#define OS_ANDROID_H
+
+#include "os/input.h"
+#include "drivers/unix/os_unix.h"
+#include "os/main_loop.h"
+#include "servers/physics/physics_server_sw.h"
+#include "servers/spatial_sound/spatial_sound_server_sw.h"
+#include "servers/spatial_sound_2d/spatial_sound_2d_server_sw.h"
+#include "servers/audio/audio_server_sw.h"
+#include "servers/physics_2d/physics_2d_server_sw.h"
+#include "servers/visual/rasterizer.h"
+
+
+#ifdef ANDROID_NATIVE_ACTIVITY
+#include "audio_driver_android.h"
+#include <android/sensor.h>
+#include <android/log.h>
+#include <android_native_app_glue.h>
+
+#else
+#include "audio_driver_jandroid.h"
+
+#endif
+
+typedef void (*GFXInitFunc)(void *ud,bool gl2);
+typedef int (*OpenURIFunc)(const String&);
+typedef String (*GetDataDirFunc)();
+typedef String (*GetLocaleFunc)();
+typedef String (*GetModelFunc)();
+typedef String (*GetUniqueIDFunc)();
+typedef void (*ShowVirtualKeyboardFunc)(const String&);
+typedef void (*HideVirtualKeyboardFunc)();
+typedef void (*SetScreenOrientationFunc)(int);
+
+class OS_Android : public OS_Unix {
+public:
+
+ struct TouchPos {
+ int id;
+ Point2 pos;
+ };
+
+private:
+
+ Vector<TouchPos> touch;
+
+ Point2 last_mouse;
+ unsigned int last_id;
+ GFXInitFunc gfx_init_func;
+ void*gfx_init_ud;
+
+ bool use_gl2;
+ bool use_reload_hooks;
+
+ Rasterizer *rasterizer;
+ VisualServer *visual_server;
+ AudioServerSW *audio_server;
+ SampleManagerMallocSW *sample_manager;
+ SpatialSoundServerSW *spatial_sound_server;
+ SpatialSound2DServerSW *spatial_sound_2d_server;
+ PhysicsServer *physics_server;
+ Physics2DServer *physics_2d_server;
+ AudioDriverAndroid audio_driver_android;
+ const char* gl_extensions;
+
+ InputDefault *input;
+ VideoMode default_videomode;
+ MainLoop * main_loop;
+
+ OpenURIFunc open_uri_func;
+ GetDataDirFunc get_data_dir_func;
+ GetLocaleFunc get_locale_func;
+ GetModelFunc get_model_func;
+ ShowVirtualKeyboardFunc show_virtual_keyboard_func;
+ HideVirtualKeyboardFunc hide_virtual_keyboard_func;
+ SetScreenOrientationFunc set_screen_orientation_func;
+ GetUniqueIDFunc get_unique_id_func;
+
+public:
+
+ // functions used by main to initialize/deintialize the OS
+ virtual int get_video_driver_count() const;
+ virtual const char * get_video_driver_name(int p_driver) const;
+
+ virtual VideoMode get_default_video_mode() const;
+
+ virtual int get_audio_driver_count() const;
+ virtual const char * get_audio_driver_name(int p_driver) const;
+
+ virtual void initialize_core();
+ virtual void initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver);
+
+ virtual void set_main_loop( MainLoop * p_main_loop );
+ virtual void delete_main_loop();
+
+ virtual void finalize();
+
+
+ typedef int64_t ProcessID;
+
+ static OS* get_singleton();
+
+ virtual void vprint(const char* p_format, va_list p_list, bool p_stderr=false);
+ virtual void print(const char *p_format, ... );
+ virtual void alert(const String& p_alert);
+
+
+ virtual void set_mouse_show(bool p_show);
+ virtual void set_mouse_grab(bool p_grab);
+ virtual bool is_mouse_grab_enabled() const;
+ virtual Point2 get_mouse_pos() const;
+ virtual int get_mouse_button_state() const;
+ virtual void set_window_title(const String& p_title);
+
+ //virtual void set_clipboard(const String& p_text);
+ //virtual String get_clipboard() const;
+
+ virtual void set_video_mode(const VideoMode& p_video_mode,int p_screen=0);
+ virtual VideoMode get_video_mode(int p_screen=0) const;
+ virtual void get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen=0) const;
+
+ virtual String get_name();
+ virtual MainLoop *get_main_loop() const;
+
+ virtual bool can_draw() const;
+
+ virtual void set_cursor_shape(CursorShape p_shape);
+
+ void main_loop_begin();
+ bool main_loop_iterate();
+ void main_loop_request_quit();
+ void main_loop_end();
+ void main_loop_focusout();
+ void main_loop_focusin();
+
+ virtual bool has_touchscreen_ui_hint() const;
+
+ virtual bool has_virtual_keyboard() const;
+ virtual void show_virtual_keyboard(const String& p_existing_text,const Rect2& p_screen_rect=Rect2());
+ virtual void hide_virtual_keyboard();
+
+ void set_opengl_extensions(const char* p_gl_extensions);
+ void set_display_size(Size2 p_size);
+
+ void reload_gfx();
+
+ void set_need_reload_hooks(bool p_needs_them);
+ virtual void set_screen_orientation(ScreenOrientation p_orientation);
+
+ virtual Error shell_open(String p_uri);
+ virtual String get_data_dir() const;
+ virtual String get_resource_dir() const;
+ virtual String get_locale() const;
+ virtual String get_model_name() const;
+
+ virtual String get_unique_ID() const;
+
+
+ void process_accelerometer(const Vector3& p_accelerometer);
+ void process_touch(int p_what,int p_pointer, const Vector<TouchPos>& p_points);
+ void process_event(InputEvent p_event);
+ void init_video_mode(int p_video_width,int p_video_height);
+ OS_Android(GFXInitFunc p_gfx_init_func,void*p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetDataDirFunc p_get_data_dir_func,GetLocaleFunc p_get_locale_func,GetModelFunc p_get_model_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, SetScreenOrientationFunc p_screen_orient,GetUniqueIDFunc p_get_unique_id);
+ ~OS_Android();
+
+};
+
+#endif
diff --git a/platform/android/platform_config.h b/platform/android/platform_config.h
new file mode 100644
index 0000000000..38fc934ae4
--- /dev/null
+++ b/platform/android/platform_config.h
@@ -0,0 +1,29 @@
+/*************************************************************************/
+/* platform_config.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include <alloca.h>
diff --git a/platform/android/project.properties.template b/platform/android/project.properties.template
new file mode 100644
index 0000000000..72bea9659c
--- /dev/null
+++ b/platform/android/project.properties.template
@@ -0,0 +1,15 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+#android.library=true
+target=android-13
diff --git a/platform/android/sign.sh b/platform/android/sign.sh
new file mode 100755
index 0000000000..830da05a37
--- /dev/null
+++ b/platform/android/sign.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+jarsigner -digestalg SHA1 -sigalg MD5withRSA -verbose -keystore my-release-key.keystore "$1" reduz
+
+echo ""
+echo ""
+echo "Checking if APK is verified..."
+jarsigner -verify "$1" -verbose -certs
+
diff --git a/platform/android/thread_jandroid.cpp b/platform/android/thread_jandroid.cpp
new file mode 100644
index 0000000000..ec6bef89a0
--- /dev/null
+++ b/platform/android/thread_jandroid.cpp
@@ -0,0 +1,135 @@
+/*************************************************************************/
+/* thread_jandroid.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "thread_jandroid.h"
+
+#include "os/memory.h"
+
+Thread::ID ThreadAndroid::get_ID() const {
+
+ return id;
+}
+
+Thread* ThreadAndroid::create_thread_jandroid() {
+
+ return memnew( ThreadAndroid );
+}
+
+void *ThreadAndroid::thread_callback(void *userdata) {
+
+ ThreadAndroid *t=reinterpret_cast<ThreadAndroid*>(userdata);
+ setup_thread();
+ t->id=(ID)pthread_self();
+ t->callback(t->user);
+ return NULL;
+}
+
+Thread* ThreadAndroid::create_func_jandroid(ThreadCreateCallback p_callback,void *p_user,const Settings&) {
+
+ ThreadAndroid *tr= memnew(ThreadAndroid);
+ tr->callback=p_callback;
+ tr->user=p_user;
+ pthread_attr_init(&tr->pthread_attr);
+ pthread_attr_setdetachstate(&tr->pthread_attr, PTHREAD_CREATE_JOINABLE);
+
+ pthread_create(&tr->pthread, &tr->pthread_attr, thread_callback, tr);
+
+ return tr;
+}
+Thread::ID ThreadAndroid::get_thread_ID_func_jandroid() {
+
+ return (ID)pthread_self();
+}
+void ThreadAndroid::wait_to_finish_func_jandroid(Thread* p_thread) {
+
+ ThreadAndroid *tp=static_cast<ThreadAndroid*>(p_thread);
+ ERR_FAIL_COND(!tp);
+ ERR_FAIL_COND(tp->pthread==0);
+
+ pthread_join(tp->pthread,NULL);
+ tp->pthread=0;
+}
+
+void ThreadAndroid::_thread_destroyed(void* value) {
+
+ /* The thread is being destroyed, detach it from the Java VM and set the mThreadKey value to NULL as required */
+ JNIEnv *env = (JNIEnv*) value;
+ if (env != NULL) {
+ java_vm->DetachCurrentThread();
+ pthread_setspecific(jvm_key, NULL);
+ }
+
+}
+
+pthread_key_t ThreadAndroid::jvm_key;
+JavaVM* ThreadAndroid::java_vm=NULL;
+
+void ThreadAndroid::setup_thread() {
+
+ if (pthread_getspecific(jvm_key))
+ return; //already setup
+ JNIEnv *env;
+ java_vm->AttachCurrentThread(&env, NULL);
+ pthread_setspecific(jvm_key, (void*) env);
+
+}
+
+void ThreadAndroid::make_default(JavaVM* p_java_vm) {
+
+ java_vm=p_java_vm;
+ create_func=create_func_jandroid;
+ get_thread_ID_func=get_thread_ID_func_jandroid;
+ wait_to_finish_func=wait_to_finish_func_jandroid;
+ pthread_key_create(&jvm_key, _thread_destroyed);
+ setup_thread();
+
+}
+
+JNIEnv *ThreadAndroid::get_env() {
+
+ if (!pthread_getspecific(jvm_key)) {
+ setup_thread();
+ }
+
+ JNIEnv *env=NULL;
+ int status = java_vm->AttachCurrentThread(&env, NULL);
+ return env;
+}
+
+
+ThreadAndroid::ThreadAndroid() {
+
+ pthread=0;
+}
+
+
+ThreadAndroid::~ThreadAndroid() {
+
+}
+
+
diff --git a/platform/android/thread_jandroid.h b/platform/android/thread_jandroid.h
new file mode 100644
index 0000000000..38b4be01ec
--- /dev/null
+++ b/platform/android/thread_jandroid.h
@@ -0,0 +1,82 @@
+/*************************************************************************/
+/* thread_jandroid.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef THREAD_POSIX_H
+#define THREAD_POSIX_H
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+
+
+#include <sys/types.h>
+#include <pthread.h>
+#include "os/thread.h"
+#include <jni.h>
+
+class ThreadAndroid : public Thread {
+
+ pthread_t pthread;
+ pthread_attr_t pthread_attr;
+ ThreadCreateCallback callback;
+ void *user;
+ ID id;
+
+ static Thread* create_thread_jandroid();
+
+
+ static void *thread_callback(void *userdata);
+
+ static Thread* create_func_jandroid(ThreadCreateCallback p_callback,void *,const Settings&);
+ static ID get_thread_ID_func_jandroid();
+ static void wait_to_finish_func_jandroid(Thread* p_thread);
+
+ static void _thread_destroyed(void* value);
+ ThreadAndroid();
+
+ static pthread_key_t jvm_key;
+ static JavaVM* java_vm;
+public:
+
+
+
+
+ virtual ID get_ID() const;
+
+ static void make_default(JavaVM* p_java_vm);
+ static void setup_thread();
+ static JNIEnv *get_env();
+
+
+ ~ThreadAndroid();
+
+};
+
+
+
+#endif