diff options
Diffstat (limited to 'platform/android')
22 files changed, 589 insertions, 537 deletions
diff --git a/platform/android/AndroidManifest.xml.template b/platform/android/AndroidManifest.xml.template index be5afb406a..9d8eb951c4 100644 --- a/platform/android/AndroidManifest.xml.template +++ b/platform/android/AndroidManifest.xml.template @@ -17,7 +17,7 @@ android:launchMode="singleTask" android:screenOrientation="landscape" android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize"> - + <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> @@ -26,7 +26,7 @@ <service android:name="org.godotengine.godot.GodotDownloaderService" /> - + $$ADD_APPLICATION_CHUNKS$$ @@ -200,6 +200,6 @@ $$ADD_PERMISSION_CHUNKS$$ <uses-permission android:name="godot.custom.18"/> <uses-permission android:name="godot.custom.19"/> -<uses-sdk android:minSdkVersion="10" android:targetSdkVersion="23"/> - -</manifest> +<uses-sdk android:minSdkVersion="18" android:targetSdkVersion="23"/> + +</manifest> diff --git a/platform/android/SCsub b/platform/android/SCsub index 87e7ee4747..7fa0262359 100644 --- a/platform/android/SCsub +++ b/platform/android/SCsub @@ -46,8 +46,18 @@ gradle_baseout = open_utf8(abspath + "/java/build.gradle", "w") gradle_text = gradle_basein.read() - +gradle_maven_flat_text = "" +if len(env.android_flat_dirs) > 0: + gradle_maven_flat_text += "flatDir {\n" + gradle_maven_flat_text += "\tdirs " + for x in env.android_flat_dirs: + gradle_maven_flat_text += "'" + x + "'," + + gradle_maven_flat_text = gradle_maven_flat_text[:-1] + gradle_maven_flat_text += "\n\t}\n" + gradle_maven_repos_text = "" +gradle_maven_repos_text += gradle_maven_flat_text if len(env.android_maven_repos) > 0: gradle_maven_repos_text += "" @@ -73,7 +83,7 @@ for x in env.android_gradle_plugins: gradle_classpath = "" for x in env.android_gradle_classpath: gradle_classpath += "\t\tclasspath \"" + x + "\"\n" - + gradle_res_dirs_text = "" for x in env.android_res_dirs: @@ -93,13 +103,13 @@ gradle_asset_dirs_text = "" gradle_default_config_text = "" -minSdk = 14 +minSdk = 18 targetSdk = 23 for x in env.android_default_config: - if x.startswith("minSdkVersion") and int(x.split(" ")[-1]) < minSdk: + if x.startswith("minSdkVersion") and int(x.split(" ")[-1]) < minSdk: x = "minSdkVersion " + str(minSdk) - if x.startswith("targetSdkVersion") and int(x.split(" ")[-1]) > targetSdk: + if x.startswith("targetSdkVersion") and int(x.split(" ")[-1]) > targetSdk: x = "targetSdkVersion " + str(targetSdk) gradle_default_config_text += x + "\n\t\t" diff --git a/platform/android/audio_driver_opensl.cpp b/platform/android/audio_driver_opensl.cpp index e774f5bb7d..9ebed84ace 100644 --- a/platform/android/audio_driver_opensl.cpp +++ b/platform/android/audio_driver_opensl.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* audio_driver_opensl.cpp */ +/* audio_driver_opensl.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ diff --git a/platform/android/build.gradle.template b/platform/android/build.gradle.template index 1df56ce621..7cb6cf860a 100644 --- a/platform/android/build.gradle.template +++ b/platform/android/build.gradle.template @@ -1,6 +1,7 @@ buildscript { repositories { jcenter() + $$GRADLE_REPOSITORY_URLS$$ } dependencies { classpath 'com.android.tools.build:gradle:2.3.3' @@ -54,11 +55,11 @@ android { ] res.srcDirs = [ 'res' - $$GRADLE_RES_DIRS$$ + $$GRADLE_RES_DIRS$$ ] aidl.srcDirs = [ 'aidl' - $$GRADLE_AIDL_DIRS$$ + $$GRADLE_AIDL_DIRS$$ ] assets.srcDirs = [ 'assets' diff --git a/platform/android/detect.py b/platform/android/detect.py index 65442bf6f8..13fc4ee810 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -18,20 +18,21 @@ def can_build(): def get_opts(): + from SCons.Variables import BoolVariable, EnumVariable return [ ('ANDROID_NDK_ROOT', 'Path to the Android NDK', os.environ.get("ANDROID_NDK_ROOT", 0)), ('ndk_platform', 'Target platform (android-<api>, e.g. "android-18")', "android-18"), - ('android_arch', 'Target architecture (armv7/armv6/arm64v8/x86)', "armv7"), - ('android_neon', 'Enable NEON support (armv7 only)', "yes"), - ('android_stl', 'Enable Android STL support (for modules)', "no") + EnumVariable('android_arch', 'Target architecture', "armv7", ('armv7', 'armv6', 'arm64v8', 'x86')), + BoolVariable('android_neon', 'Enable NEON support (armv7 only)', True), + BoolVariable('android_stl', 'Enable Android STL support (for modules)', False), ] def get_flags(): return [ - ('tools', 'no'), + ('tools', False), ] @@ -93,7 +94,7 @@ def configure(env): env['android_arch'] = 'armv7' neon_text = "" - if env["android_arch"] == "armv7" and env['android_neon'] == 'yes': + if env["android_arch"] == "armv7" and env['android_neon']: neon_text = " (with NEON)" print("Building for Android (" + env['android_arch'] + ")" + neon_text) @@ -117,7 +118,7 @@ def configure(env): target_subpath = "arm-linux-androideabi-4.9" abi_subpath = "arm-linux-androideabi" arch_subpath = "armeabi-v7a" - if env['android_neon'] == 'yes': + if env['android_neon']: env.extra_suffix = ".armv7.neon" + env.extra_suffix else: env.extra_suffix = ".armv7" + env.extra_suffix @@ -199,7 +200,7 @@ def configure(env): elif env["android_arch"] == "armv7": target_opts = ['-target', 'armv7-none-linux-androideabi'] env.Append(CPPFLAGS='-D__ARM_ARCH_7__ -D__ARM_ARCH_7A__ -march=armv7-a -mfloat-abi=softfp'.split()) - if env['android_neon'] == 'yes': + if env['android_neon']: env['neon_enabled'] = True env.Append(CPPFLAGS=['-mfpu=neon', '-D__ARM_NEON__']) else: @@ -213,7 +214,7 @@ def configure(env): env.Append(CPPFLAGS=target_opts) env.Append(CPPFLAGS=common_opts) - if (env['android_stl'] == 'yes'): + if env['android_stl']: env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/gnu-libstdc++/4.9/include"]) env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/gnu-libstdc++/4.9/libs/" + arch_subpath + "/include"]) env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/gnu-libstdc++/4.9/libs/" + arch_subpath]) @@ -240,10 +241,10 @@ def configure(env): env.Append(CPPPATH=['#platform/android']) env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED', '-DNO_FCNTL', '-DMPC_FIXED_POINT']) - env.Append(LIBS=['OpenSLES', 'EGL', 'GLESv3', 'android', 'log', 'z']) + env.Append(LIBS=['OpenSLES', 'EGL', 'GLESv3', 'android', 'log', 'z', 'dl']) # TODO: Move that to opus module's config - if("module_opus_enabled" in env and env["module_opus_enabled"] != "no"): + if 'module_opus_enabled' in env and env['module_opus_enabled']: if (env["android_arch"] == "armv6" or env["android_arch"] == "armv7"): env.Append(CFLAGS=["-DOPUS_ARM_OPT"]) env.opus_fixed_point = "yes" diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 8b3a64bbe6..79be1501a7 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -204,7 +204,7 @@ class EditorExportAndroid : public EditorExportPlatform { String id; String name; String description; - int release; + int api_level; }; struct APKExportData { @@ -267,7 +267,6 @@ class EditorExportAndroid : public EditorExportPlatform { if (different) { - print_line("DIFFERENT!"); Vector<Device> ndevices; for (int i = 0; i < ldevices.size(); i++) { @@ -278,7 +277,7 @@ class EditorExportAndroid : public EditorExportPlatform { if (ea->devices[j].id == ldevices[i]) { d.description = ea->devices[j].description; d.name = ea->devices[j].name; - d.release = ea->devices[j].release; + d.api_level = ea->devices[j].api_level; } } @@ -299,7 +298,7 @@ class EditorExportAndroid : public EditorExportPlatform { String vendor; String device; d.description + "Device ID: " + d.id + "\n"; - d.release = 0; + d.api_level = 0; for (int j = 0; j < props.size(); j++) { String p = props[j]; @@ -310,9 +309,9 @@ class EditorExportAndroid : public EditorExportPlatform { } 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=")) { - const String release_str = p.get_slice("=", 1).strip_edges(); - d.description += "Release: " + release_str + "\n"; - d.release = release_str.to_int(); + d.description += "Release: " + p.get_slice("=", 1).strip_edges() + "\n"; + } else if (p.begins_with("ro.build.version.sdk=")) { + d.api_level = p.get_slice("=", 1).to_int(); } 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=")) { @@ -468,11 +467,36 @@ class EditorExportAndroid : public EditorExportPlatform { return zipfi; } - static Error save_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total) { + static Set<String> get_abis() { + Set<String> abis; + abis.insert("armeabi"); + abis.insert("armeabi-v7a"); + abis.insert("arm64-v8a"); + abis.insert("x86"); + abis.insert("x86_64"); + abis.insert("mips"); + abis.insert("mips64"); + return abis; + } + static Error 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/"); + static Set<String> android_abis = get_abis(); + + if (dst_path.ends_with(".so")) { + String abi = dst_path.get_base_dir().get_file().strip_edges(); // parent dir name + if (android_abis.has(abi)) { + dst_path = "lib/" + abi + "/" + dst_path.get_file(); + } else { + String err = "Dynamic libraries must be located in the folder named after Android ABI they were compiled for. " + + p_path + " does not follow this convention."; + ERR_PRINT(err.utf8().get_data()); + return ERR_FILE_BAD_PATH; + } + } else { + dst_path = dst_path.replace_first("res://", "assets/"); + } zip_fileinfo zipfi = get_zip_fileinfo(); @@ -495,34 +519,30 @@ class EditorExportAndroid : public EditorExportPlatform { void _fix_manifest(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_manifest, bool p_give_internet) { - const int CHUNK_AXML_FILE = 0x00080003; - const int CHUNK_RESOURCEIDS = 0x00080180; + // Leaving the unused types commented because looking these constants up + // again later would be annoying + // 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_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 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; + uint32_t ofs = 8; - //print_line("FILESIZE: "+itos(filesize)+" ACTUAL: "+itos(p_manifest.size())); + uint32_t string_count = 0; + uint32_t styles_count = 0; + uint32_t string_flags = 0; + uint32_t string_data_offset = 0; - 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; + uint32_t styles_offset = 0; + uint32_t string_table_begins = 0; + uint32_t string_table_ends = 0; Vector<uint8_t> stable_extra; String version_name = p_preset->get("version/name"); @@ -621,24 +641,16 @@ class EditorExportAndroid : public EditorExportPlatform { 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 (uint32_t 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; @@ -653,12 +665,6 @@ class EditorExportAndroid : public EditorExportPlatform { 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") { @@ -666,9 +672,6 @@ class EditorExportAndroid : public EditorExportPlatform { string_table[attr_value] = get_package_name(package_name); } - //print_line("tname: "+tname); - //print_line("nspace: "+nspace); - //print_line("attrname: "+attrname); if (tname == "manifest" && /*nspace=="android" &&*/ attrname == "versionCode") { print_line("FOUND versionCode"); @@ -687,13 +690,6 @@ class EditorExportAndroid : public EditorExportPlatform { if (tname == "activity" && /*nspace=="android" &&*/ attrname == "screenOrientation") { encode_uint32(orientation == 0 ? 0 : 1, &p_manifest[iofs + 16]); - /* - 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 == "uses-feature" && /*nspace=="android" &&*/ attrname == "glEsVersion") { @@ -746,13 +742,10 @@ class EditorExportAndroid : public EditorExportPlatform { } break; } - //printf("chunk %x: size: %d\n",chunk,size); ofs += size; } - //printf("end\n"); - //create new andriodmanifest binary Vector<uint8_t> ret; @@ -851,8 +844,6 @@ class EditorExportAndroid : public EditorExportPlatform { 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]); @@ -862,10 +853,6 @@ class EditorExportAndroid : public EditorExportPlatform { String package_name = p_preset->get("package/name"); - //printf("stirng block len: %i\n",string_block_len); - //printf("stirng count: %i\n",string_count); - //printf("flags: %x\n",string_flags); - for (uint32_t i = 0; i < string_count; i++) { uint32_t offset = decode_uint32(&p_manifest[string_table_begins + i * 4]); @@ -883,7 +870,7 @@ class EditorExportAndroid : public EditorExportPlatform { String lang = str.substr(str.find_last("-") + 1, str.length()).replace("-", "_"); String prop = "application/config/name_" + lang; - if (ProjectSettings::get_singleton()->has(prop)) { + if (ProjectSettings::get_singleton()->has_setting(prop)) { str = ProjectSettings::get_singleton()->get(prop); } else { str = get_project_name(package_name); @@ -1073,7 +1060,11 @@ public: //export_temp ep.step("Exporting APK", 0); - p_debug_flags |= DEBUG_FLAG_REMOTE_DEBUG_LOCALHOST; + const bool use_remote = (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) || (p_debug_flags & DEBUG_FLAG_DUMB_CLIENT); + const bool use_reverse = devices[p_device].api_level >= 21; + + if (use_reverse) + p_debug_flags |= DEBUG_FLAG_REMOTE_DEBUG_LOCALHOST; String export_to = EditorSettings::get_singleton()->get_settings_path() + "/tmp/tmpexport.apk"; Error err = export_project(p_preset, true, export_to, p_debug_flags); @@ -1119,40 +1110,54 @@ public: return ERR_CANT_CREATE; } - if (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) { + if (use_remote) { + if (use_reverse) { - args.clear(); - args.push_back("-s"); - args.push_back(devices[p_device].id); - args.push_back("reverse"); - args.push_back("--remove-all"); - OS::get_singleton()->execute(adb, args, true, NULL, NULL, &rv); + static const char *const msg = "** Device API >= 21; debugging over USB **"; + EditorNode::get_singleton()->get_log()->add_message(msg); + print_line(String(msg).to_upper()); - int dbg_port = EditorSettings::get_singleton()->get("network/debug/remote_port"); - args.clear(); - args.push_back("-s"); - args.push_back(devices[p_device].id); - args.push_back("reverse"); - args.push_back("tcp:" + itos(dbg_port)); - args.push_back("tcp:" + itos(dbg_port)); + args.clear(); + args.push_back("-s"); + args.push_back(devices[p_device].id); + args.push_back("reverse"); + args.push_back("--remove-all"); + OS::get_singleton()->execute(adb, args, true, NULL, NULL, &rv); - OS::get_singleton()->execute(adb, args, true, NULL, NULL, &rv); - print_line("Reverse result: " + itos(rv)); - } + if (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) { - if (p_debug_flags & DEBUG_FLAG_DUMB_CLIENT) { + int dbg_port = EditorSettings::get_singleton()->get("network/debug/remote_port"); + args.clear(); + args.push_back("-s"); + args.push_back(devices[p_device].id); + args.push_back("reverse"); + args.push_back("tcp:" + itos(dbg_port)); + args.push_back("tcp:" + itos(dbg_port)); - int fs_port = EditorSettings::get_singleton()->get("filesystem/file_server/port"); + OS::get_singleton()->execute(adb, args, true, NULL, NULL, &rv); + print_line("Reverse result: " + itos(rv)); + } - args.clear(); - args.push_back("-s"); - args.push_back(devices[p_device].id); - args.push_back("reverse"); - args.push_back("tcp:" + itos(fs_port)); - args.push_back("tcp:" + itos(fs_port)); + if (p_debug_flags & DEBUG_FLAG_DUMB_CLIENT) { - err = OS::get_singleton()->execute(adb, args, true, NULL, NULL, &rv); - print_line("Reverse result2: " + itos(rv)); + int fs_port = EditorSettings::get_singleton()->get("filesystem/file_server/port"); + + args.clear(); + args.push_back("-s"); + args.push_back(devices[p_device].id); + args.push_back("reverse"); + args.push_back("tcp:" + itos(fs_port)); + args.push_back("tcp:" + itos(fs_port)); + + err = OS::get_singleton()->execute(adb, args, true, NULL, NULL, &rv); + print_line("Reverse result2: " + itos(rv)); + } + } else { + + static const char *const msg = "** Device API < 21; debugging over Wi-Fi **"; + EditorNode::get_singleton()->get_log()->add_message(msg); + print_line(String(msg).to_upper()); + } } ep.step("Running on Device..", 3); @@ -1162,7 +1167,7 @@ public: args.push_back("shell"); args.push_back("am"); args.push_back("start"); - if ((bool)EditorSettings::get_singleton()->get("export/android/force_system_user") && devices[p_device].release >= 17) { // Multi-user introduced in Android 17 + if ((bool)EditorSettings::get_singleton()->get("export/android/force_system_user") && devices[p_device].api_level >= 17) { // Multi-user introduced in Android 17 args.push_back("--user"); args.push_back("0"); } @@ -1375,15 +1380,15 @@ public: } } - if (file == "lib/x86/libgodot_android.so" && !export_x86) { + if (file == "lib/x86/*.so" && !export_x86) { skip = true; } - if (file.match("lib/armeabi*/libgodot_android.so") && !export_arm) { + if (file.match("lib/armeabi*/*.so") && !export_arm) { skip = true; } - if (file.match("lib/arm64*/libgodot_android.so") && !export_arm64) { + if (file.match("lib/arm64*/*.so") && !export_arm64) { skip = true; } diff --git a/platform/android/file_access_android.cpp b/platform/android/file_access_android.cpp index f207b81b4b..0fdf9002d7 100644 --- a/platform/android/file_access_android.cpp +++ b/platform/android/file_access_android.cpp @@ -95,7 +95,7 @@ void FileAccessAndroid::seek_end(int64_t p_position) { pos = len + p_position; } -size_t FileAccessAndroid::get_pos() const { +size_t FileAccessAndroid::get_position() const { return pos; } @@ -146,6 +146,11 @@ Error FileAccessAndroid::get_error() const { return eof ? ERR_FILE_EOF : OK; //not sure what else it may happen } +void FileAccessAndroid::flush() { + + ERR_FAIL(); +} + void FileAccessAndroid::store_8(uint8_t p_dest) { ERR_FAIL(); diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h index c2ce2b0bfe..c8fedbe684 100644 --- a/platform/android/file_access_android.h +++ b/platform/android/file_access_android.h @@ -53,7 +53,7 @@ public: 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_position() 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 @@ -63,6 +63,7 @@ public: virtual Error get_error() const; ///< get last error + virtual void flush(); 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 diff --git a/platform/android/file_access_jandroid.cpp b/platform/android/file_access_jandroid.cpp index ad855c790d..980afd8f46 100644 --- a/platform/android/file_access_jandroid.cpp +++ b/platform/android/file_access_jandroid.cpp @@ -106,7 +106,7 @@ void FileAccessJAndroid::seek_end(int64_t p_position) { seek(get_len()); } -size_t FileAccessJAndroid::get_pos() const { +size_t FileAccessJAndroid::get_position() const { JNIEnv *env = ThreadAndroid::get_env(); ERR_FAIL_COND_V(!is_open(), 0); @@ -157,6 +157,9 @@ Error FileAccessJAndroid::get_error() const { return OK; } +void FileAccessJAndroid::flush() { +} + void FileAccessJAndroid::store_8(uint8_t p_dest) { } diff --git a/platform/android/file_access_jandroid.h b/platform/android/file_access_jandroid.h index 8060312182..368d2c98fa 100644 --- a/platform/android/file_access_jandroid.h +++ b/platform/android/file_access_jandroid.h @@ -57,7 +57,7 @@ public: 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_position() 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 @@ -67,6 +67,7 @@ public: virtual Error get_error() const; ///< get last error + virtual void flush(); 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 diff --git a/platform/android/java/src/org/godotengine/godot/Godot.java b/platform/android/java/src/org/godotengine/godot/Godot.java index eab0387f32..59fefc498f 100644 --- a/platform/android/java/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/src/org/godotengine/godot/Godot.java @@ -92,7 +92,7 @@ import android.os.SystemClock; public class Godot extends Activity implements SensorEventListener, IDownloaderClient -{ +{ static final int MAX_SINGLETONS = 64; private IStub mDownloaderClientStub; @@ -139,9 +139,9 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC com.godot.game.R.string.text_button_pause; mPauseButton.setText(stringResourceID); } - + static public class SingletonBase { - + protected void registerClass(String p_name, String[] p_methods) { GodotLib.singleton(p_name,this); @@ -191,6 +191,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC protected void onMainPause() {} protected void onMainResume() {} protected void onMainDestroy() {} + protected boolean onMainBackPressed() { return false; } protected void onGLDrawFrame(GL10 gl) {} protected void onGLSurfaceChanged(GL10 gl, int width, int height) {} // singletons will always miss first onGLSurfaceChanged call @@ -210,6 +211,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC */ private String[] command_line; + private boolean use_apk_expansion; public GodotView mView; private boolean godot_initialized=false; @@ -264,27 +266,55 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC layout = new FrameLayout(this); layout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT)); setContentView(layout); - + // GodotEditText layout - GodotEditText edittext = new GodotEditText(this); + GodotEditText edittext = new GodotEditText(this); edittext.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT)); // ...add to FrameLayout layout.addView(edittext); - + mView = new GodotView(getApplication(),io,use_gl2,use_32_bits, this); layout.addView(mView,new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT)); - setKeepScreenOn(GodotLib.getGlobal("display/driver/keep_screen_on").equals("True")); - - edittext.setView(mView); - io.setEdit(edittext); - + edittext.setView(mView); + io.setEdit(edittext); + + final Godot godot = this; + mView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + Point fullSize = new Point(); + godot.getWindowManager().getDefaultDisplay().getSize(fullSize); + Rect gameSize = new Rect(); + godot.mView.getWindowVisibleDisplayFrame(gameSize); + + final int keyboardHeight = fullSize.y - gameSize.bottom; + Log.d("GODOT", "setVirtualKeyboardHeight: " + keyboardHeight); + GodotLib.setVirtualKeyboardHeight(keyboardHeight); + } + }); + // Ad layout adLayout = new RelativeLayout(this); adLayout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT)); layout.addView(adLayout); - + + final String[] current_command_line = command_line; + final GodotView view = mView; + mView.queueEvent(new Runnable() { + @Override + public void run() { + GodotLib.setup(current_command_line); + runOnUiThread(new Runnable() { + @Override + public void run() { + view.setKeepScreenOn("True".equals(GodotLib.getGlobal("display/driver/keep_screen_on"))); + } + }); + } + }); + } - + public void setKeepScreenOn(final boolean p_enabled) { keep_screen_on = p_enabled; if (mView != null){ @@ -315,13 +345,13 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC } }); } - + private static Godot _self; - + public static Godot getInstance(){ return Godot._self; } - + private String[] getCommandLine() { InputStream is; @@ -402,7 +432,6 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC Log.d("GODOT"," " + command_line[w]); } }*/ - GodotLib.initialize(this,io.needsReloadHooks(),command_line,getAssets()); mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME); @@ -411,9 +440,12 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC mGyroscope = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); mSensorManager.registerListener(this, mGyroscope, SensorManager.SENSOR_DELAY_GAME); + GodotLib.initialize(this, io.needsReloadHooks(), getAssets(), use_apk_expansion); + result_callback = null; mPaymentsManager = PaymentsManager.createManager(this).initService(); + godot_initialized=true; } @@ -426,7 +458,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC - @Override + @Override protected void onCreate(Bundle icicle) { Log.d("GODOT", "** GODOT ACTIVITY CREATED HERE ***\n"); @@ -437,12 +469,10 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC //window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON); - //check for apk expansion API if (true) { boolean md5mismatch = false; command_line = getCommandLine(); - boolean use_apk_expansion=false; String main_pack_md5=null; String main_pack_key=null; @@ -528,23 +558,23 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC if (!pack_valid) { Log.d("GODOT", "Pack Invalid, try re-downloading."); - + Intent notifierIntent = new Intent(this, this.getClass()); notifierIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); - + PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notifierIntent, PendingIntent.FLAG_UPDATE_CURRENT); - + int startResult; try { Log.d("GODOT", "INITIALIZING DOWNLOAD"); startResult = DownloaderClientMarshaller.startDownloadServiceIfRequired( - getApplicationContext(), - pendingIntent, + getApplicationContext(), + pendingIntent, GodotDownloaderService.class); Log.d("GODOT", "DOWNLOAD SERVICE FINISHED:" + startResult); - + if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) { Log.d("GODOT", "DOWNLOAD REQUIRED"); // This is where you do set up to display the download @@ -563,7 +593,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC mCellMessage = findViewById(com.godot.game.R.id.approveCellular); mPauseButton = (Button) findViewById(com.godot.game.R.id.pauseButton); mWiFiSettingsButton = (Button) findViewById(com.godot.game.R.id.wifiSettingsButton); - + return; } else{ Log.d("GODOT", "NO DOWNLOAD REQUIRED"); @@ -582,7 +612,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC initializeGodot(); - + //instanceSingleton( new GodotFacebook(this) ); @@ -590,14 +620,14 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC @Override protected void onDestroy(){ - + if(mPaymentsManager != null ) mPaymentsManager.destroy(); for(int i=0;i<singleton_count;i++) { singletons[i].onMainDestroy(); } super.onDestroy(); } - + @Override protected void onPause() { super.onPause(); if (!godot_initialized){ @@ -607,8 +637,13 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC return; } mView.onPause(); + mView.queueEvent(new Runnable() { + @Override + public void run() { + GodotLib.focusout(); + } + }); mSensorManager.unregisterListener(this); - GodotLib.focusout(); for(int i=0;i<singleton_count;i++) { singletons[i].onMainPause(); @@ -625,10 +660,16 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC } mView.onResume(); + mView.queueEvent(new Runnable() { + @Override + public void run() { + GodotLib.focusin(); + } + }); mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME); mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_GAME); mSensorManager.registerListener(this, mGyroscope, SensorManager.SENSOR_DELAY_GAME); - GodotLib.focusin(); + if(use_immersive && Build.VERSION.SDK_INT >= 19.0){ // check if the application runs on an android 4.4+ Window window = getWindow(); window.getDecorView().setSystemUiVisibility( @@ -644,8 +685,8 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC singletons[i].onMainResume(); } - - + + } @@ -670,32 +711,39 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC @Override public void onSensorChanged(SensorEvent event) { Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay(); int displayRotation = display.getRotation(); - + float[] adjustedValues = new float[3]; final int axisSwap[][] = { - { 1, -1, 0, 1 }, // ROTATION_0 - {-1, -1, 1, 0 }, // ROTATION_90 - {-1, 1, 0, 1 }, // ROTATION_180 - { 1, 1, 1, 0 } }; // ROTATION_270 - - final int[] as = axisSwap[displayRotation]; - adjustedValues[0] = (float)as[0] * event.values[ as[2] ]; - adjustedValues[1] = (float)as[1] * event.values[ as[3] ]; + { 1, -1, 0, 1 }, // ROTATION_0 + {-1, -1, 1, 0 }, // ROTATION_90 + {-1, 1, 0, 1 }, // ROTATION_180 + { 1, 1, 1, 0 } }; // ROTATION_270 + + final int[] as = axisSwap[displayRotation]; + adjustedValues[0] = (float)as[0] * event.values[ as[2] ]; + adjustedValues[1] = (float)as[1] * event.values[ as[3] ]; adjustedValues[2] = event.values[2]; - - float x = adjustedValues[0]; - float y = adjustedValues[1]; - float z = adjustedValues[2]; - - int typeOfSensor = event.sensor.getType(); - if (typeOfSensor == event.sensor.TYPE_ACCELEROMETER) { - GodotLib.accelerometer(x,y,z); - } - if (typeOfSensor == event.sensor.TYPE_MAGNETIC_FIELD) { - GodotLib.magnetometer(x,y,z); - } - if (typeOfSensor == event.sensor.TYPE_GYROSCOPE) { - GodotLib.gyroscope(x,y,z); + + final float x = adjustedValues[0]; + final float y = adjustedValues[1]; + final float z = adjustedValues[2]; + + final int typeOfSensor = event.sensor.getType(); + if (mView != null) { + mView.queueEvent(new Runnable() { + @Override + public void run() { + if (typeOfSensor == Sensor.TYPE_ACCELEROMETER) { + GodotLib.accelerometer(x,y,z); + } + if (typeOfSensor == Sensor.TYPE_MAGNETIC_FIELD) { + GodotLib.magnetometer(x,y,z); + } + if (typeOfSensor == Sensor.TYPE_GYROSCOPE) { + GodotLib.gyroscope(x,y,z); + } + } + }); } } @@ -720,9 +768,23 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC */ @Override public void onBackPressed() { + boolean shouldQuit = true; + + for(int i=0;i<singleton_count;i++) { + if (singletons[i].onMainBackPressed()) { + shouldQuit = false; + } + } System.out.printf("** BACK REQUEST!\n"); - //GodotLib.back(); + if (shouldQuit && mView != null) { + mView.queueEvent(new Runnable() { + @Override + public void run() { + GodotLib.back(); + } + }); + } } public void forceQuit() { @@ -733,7 +795,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC private boolean obbIsCorrupted(String f, String main_pack_md5){ - + try { InputStream fis = new FileInputStream(f); @@ -780,58 +842,64 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC } //@Override public boolean dispatchTouchEvent (MotionEvent event) { - public boolean gotTouchEvent(MotionEvent event) { + public boolean gotTouchEvent(final MotionEvent event) { super.onTouchEvent(event); - int evcount=event.getPointerCount(); + final int evcount=event.getPointerCount(); if (evcount==0) return true; - int[] arr = new int[event.getPointerCount()*3]; + if (mView != null) { + final int[] arr = new int[event.getPointerCount()*3]; - for(int i=0;i<event.getPointerCount();i++) { + 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); - } + 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: { - final int indexPointUp = event.getActionIndex(); - final int pointer_idx = event.getPointerId(indexPointUp); - 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)); + //System.out.printf("gaction: %d\n",event.getAction()); + final int action = event.getAction() & MotionEvent.ACTION_MASK; + mView.queueEvent(new Runnable() { + @Override + public void run() { + switch(action) { + 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: { + final int indexPointUp = event.getActionIndex(); + final int pointer_idx = event.getPointerId(indexPointUp); + 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; + } } - */ - } break; - + }); } return true; } @@ -864,7 +932,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC private void queueEvent(Runnable runnable) { // TODO Auto-generated method stub - + } public PaymentsManager getPaymentsManager() { @@ -988,7 +1056,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC mProgressFraction.setText(Helpers.getDownloadProgressString (progress.mOverallProgress, progress.mOverallTotal)); - + } - + } diff --git a/platform/android/java/src/org/godotengine/godot/GodotLib.java b/platform/android/java/src/org/godotengine/godot/GodotLib.java index b487c17f53..e0ed4cd38c 100644 --- a/platform/android/java/src/org/godotengine/godot/GodotLib.java +++ b/platform/android/java/src/org/godotengine/godot/GodotLib.java @@ -37,7 +37,7 @@ public class GodotLib { public static GodotIO io; static { - System.loadLibrary("godot_android"); + System.loadLibrary("godot_android"); } /** @@ -45,7 +45,8 @@ public class GodotLib { * @param height the current view height */ - public static native void initialize(Godot p_instance,boolean need_reload_hook,String[] p_cmdline,Object p_asset_manager); + public static native void initialize(Godot p_instance,boolean need_reload_hook,Object p_asset_manager, boolean use_apk_expansion); + public static native void setup(String[] p_cmdline); public static native void resize(int width, int height,boolean reload); public static native void newcontext(boolean p_32_bits); public static native void back(); @@ -68,4 +69,6 @@ public class GodotLib { public static native void callobject(int p_ID, String p_method, Object[] p_params); public static native void calldeferred(int p_ID, String p_method, Object[] p_params); + public static native void setVirtualKeyboardHeight(int p_height); + } diff --git a/platform/android/java/src/org/godotengine/godot/GodotPaymentV3.java b/platform/android/java/src/org/godotengine/godot/GodotPaymentV3.java index a16c67523e..8fe79fdfc7 100644 --- a/platform/android/java/src/org/godotengine/godot/GodotPaymentV3.java +++ b/platform/android/java/src/org/godotengine/godot/GodotPaymentV3.java @@ -89,7 +89,7 @@ public class GodotPaymentV3 extends Godot.SingletonBase { } public void callbackSuccess(String ticket, String signature, String sku) { - GodotLib.callobject(purchaseCallbackId, "purchase_success", new Object[]{ticket, signature, sku}); + GodotLib.calldeferred(purchaseCallbackId, "purchase_success", new Object[]{ticket, signature, sku}); } public void callbackSuccessProductMassConsumed(String ticket, String signature, String sku) { diff --git a/platform/android/java/src/org/godotengine/godot/GodotView.java b/platform/android/java/src/org/godotengine/godot/GodotView.java index 19fcf8e687..b807b952d4 100644 --- a/platform/android/java/src/org/godotengine/godot/GodotView.java +++ b/platform/android/java/src/org/godotengine/godot/GodotView.java @@ -208,8 +208,9 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { @Override public void onInputDeviceAdded(int deviceId) { joystick joy = new joystick(); joy.device_id = deviceId; - int id = joy_devices.size(); + final int id = joy_devices.size(); InputDevice device = mInputManager.getInputDevice(deviceId); + final String name = device.getName(); joy.name = device.getName(); joy.axes = new ArrayList<InputDevice.MotionRange>(); joy.hats = new ArrayList<InputDevice.MotionRange>(); @@ -224,19 +225,29 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { } } joy_devices.add(joy); - GodotLib.joyconnectionchanged(id, true, joy.name); + queueEvent(new Runnable() { + @Override + public void run() { + GodotLib.joyconnectionchanged(id, true, name); + } + }); } @Override public void onInputDeviceRemoved(int deviceId) { - int id = find_joy_device(deviceId); + final int id = find_joy_device(deviceId); joy_devices.remove(id); - GodotLib.joyconnectionchanged(id, false, ""); + queueEvent(new Runnable() { + @Override + public void run() { + GodotLib.joyconnectionchanged(id, false, ""); + } + }); } @Override public void onInputDeviceChanged(int deviceId) { } - @Override public boolean onKeyUp(int keyCode, KeyEvent event) { + @Override public boolean onKeyUp(final int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { return true; @@ -249,22 +260,32 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { int source = event.getSource(); if ((source & InputDevice.SOURCE_JOYSTICK) != 0 || (source & InputDevice.SOURCE_DPAD) != 0 || (source & InputDevice.SOURCE_GAMEPAD) != 0) { - int button = get_godot_button(keyCode); - int device = find_joy_device(event.getDeviceId()); + final int button = get_godot_button(keyCode); + final int device = find_joy_device(event.getDeviceId()); - GodotLib.joybutton(device, button, false); + queueEvent(new Runnable() { + @Override + public void run() { + GodotLib.joybutton(device, button, false); + } + }); return true; } else { - - GodotLib.key(keyCode, event.getUnicodeChar(0), false); + final int chr = event.getUnicodeChar(0); + queueEvent(new Runnable() { + @Override + public void run() { + GodotLib.key(keyCode, chr, false); + } + }); }; return super.onKeyUp(keyCode, event); }; - @Override public boolean onKeyDown(int keyCode, KeyEvent event) { + @Override public boolean onKeyDown(final int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { - GodotLib.back(); + activity.onBackPressed(); // press 'back' button should not terminate program //normal handle 'back' event in game logic return true; @@ -281,16 +302,26 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { if (event.getRepeatCount() > 0) // ignore key echo return true; - int button = get_godot_button(keyCode); - int device = find_joy_device(event.getDeviceId()); + final int button = get_godot_button(keyCode); + final int device = find_joy_device(event.getDeviceId()); //Log.e(TAG, String.format("joy button down! button %x, %d, device %d", keyCode, button, device)); - - GodotLib.joybutton(device, button, true); + queueEvent(new Runnable() { + @Override + public void run() { + GodotLib.joybutton(device, button, true); + } + }); return true; } else { - GodotLib.key(keyCode, event.getUnicodeChar(0), true); + final int chr = event.getUnicodeChar(0); + queueEvent(new Runnable() { + @Override + public void run() { + GodotLib.key(keyCode, chr, true); + } + }); }; return super.onKeyDown(keyCode, event); } @@ -299,21 +330,32 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK && event.getAction() == MotionEvent.ACTION_MOVE) { - int device_id = find_joy_device(event.getDeviceId()); + final int device_id = find_joy_device(event.getDeviceId()); joystick joy = joy_devices.get(device_id); for (int i = 0; i < joy.axes.size(); i++) { InputDevice.MotionRange range = joy.axes.get(i); - float value = (event.getAxisValue(range.getAxis()) - range.getMin() ) / range.getRange() * 2.0f - 1.0f; + final float value = (event.getAxisValue(range.getAxis()) - range.getMin() ) / range.getRange() * 2.0f - 1.0f; //Log.e(TAG, String.format("axis event: %d, value %f", i, value)); - GodotLib.joyaxis(device_id, i, value); + final int idx = i; + queueEvent(new Runnable() { + @Override + public void run() { + GodotLib.joyaxis(device_id, idx, value); + } + }); } for (int i = 0; i < joy.hats.size(); i+=2) { - int hatX = Math.round(event.getAxisValue(joy.hats.get(i).getAxis())); - int hatY = Math.round(event.getAxisValue(joy.hats.get(i+1).getAxis())); + final int hatX = Math.round(event.getAxisValue(joy.hats.get(i).getAxis())); + final int hatY = Math.round(event.getAxisValue(joy.hats.get(i+1).getAxis())); //Log.e(TAG, String.format("HAT EVENT %d, %d", hatX, hatY)); - GodotLib.joyhat(device_id, hatX, hatY); + queueEvent(new Runnable() { + @Override + public void run() { + GodotLib.joyhat(device_id, hatX, hatY); + } + }); } return true; }; diff --git a/platform/android/java/src/org/godotengine/godot/input/GodotTextInputWrapper.java b/platform/android/java/src/org/godotengine/godot/input/GodotTextInputWrapper.java index c2d03e4ecc..ac424ab9f8 100644 --- a/platform/android/java/src/org/godotengine/godot/input/GodotTextInputWrapper.java +++ b/platform/android/java/src/org/godotengine/godot/input/GodotTextInputWrapper.java @@ -88,60 +88,50 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene public void beforeTextChanged(final CharSequence pCharSequence, final int start, final int count, final int after) { //Log.d(TAG, "beforeTextChanged(" + pCharSequence + ")start: " + start + ",count: " + count + ",after: " + after); - for (int i=0;i<count;i++){ - GodotLib.key(KeyEvent.KEYCODE_DEL, 0, true); - GodotLib.key(KeyEvent.KEYCODE_DEL, 0, false); - } + mView.queueEvent(new Runnable() { + @Override + public void run() { + for (int i = 0; i < count; ++i) { + GodotLib.key(KeyEvent.KEYCODE_DEL, 0, true); + GodotLib.key(KeyEvent.KEYCODE_DEL, 0, false); + } + } + }); } @Override public void onTextChanged(final CharSequence pCharSequence, final int start, final int before, final int count) { //Log.d(TAG, "onTextChanged(" + pCharSequence + ")start: " + start + ",count: " + count + ",before: " + before); - for (int i=start;i<start+count;i++){ - int ch = pCharSequence.charAt(i); - GodotLib.key(0, ch, true); - GodotLib.key(0, ch, false); - } - + mView.queueEvent(new Runnable() { + @Override + public void run() { + for (int i = start; i < start + count; ++i) { + final int ch = pCharSequence.charAt(i); + GodotLib.key(0, ch, true); + GodotLib.key(0, ch, false); + } + } + }); } @Override public boolean onEditorAction(final TextView pTextView, final int pActionID, final KeyEvent pKeyEvent) { if (this.mEdit == pTextView && this.isFullScreenEdit()) { - // user press the action button, delete all old text and insert new text - for (int i = this.mOriginText.length(); i > 0; i--) { - GodotLib.key(KeyEvent.KEYCODE_DEL, 0, true); - GodotLib.key(KeyEvent.KEYCODE_DEL, 0, false); - /* - if (BuildConfig.DEBUG) { - Log.d(TAG, "deleteBackward"); + final String characters = pKeyEvent.getCharacters(); + + mView.queueEvent(new Runnable() { + @Override + public void run() { + for (int i = 0; i < characters.length(); i++) { + final int ch = characters.codePointAt(i); + GodotLib.key(0, ch, true); + GodotLib.key(0, ch, false); + } } - */ - } - String text = pTextView.getText().toString(); - - /* If user input nothing, translate "\n" to engine. */ - if (text.compareTo("") == 0) { - text = "\n"; - } - - if ('\n' != text.charAt(text.length() - 1)) { - text += '\n'; - } - - for(int i = 0; i < text.length(); i++) { - int ch = text.codePointAt(i); - GodotLib.key(0, ch, true); - GodotLib.key(0, ch, false); - } - /* - if (BuildConfig.DEBUG) { - Log.d(TAG, "insertText(" + insertText + ")"); - } - */ + }); } - + if (pActionID == EditorInfo.IME_ACTION_DONE) { this.mView.requestFocus(); } diff --git a/platform/android/java/src/org/godotengine/godot/utils/CustomSSLSocketFactory.java b/platform/android/java/src/org/godotengine/godot/utils/CustomSSLSocketFactory.java index c9532a5d01..3fc8c48397 100644 --- a/platform/android/java/src/org/godotengine/godot/utils/CustomSSLSocketFactory.java +++ b/platform/android/java/src/org/godotengine/godot/utils/CustomSSLSocketFactory.java @@ -36,12 +36,9 @@ import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; +import javax.net.ssl.TrustManagerFactory; import org.apache.http.conn.ssl.SSLSocketFactory; @@ -56,19 +53,10 @@ public class CustomSSLSocketFactory extends SSLSocketFactory { public CustomSSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { super(truststore); - TrustManager tm = new X509TrustManager() { - public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { - } + TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509"); + tmf.init(truststore); - public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { - } - - public X509Certificate[] getAcceptedIssuers() { - return null; - } - }; - - sslContext.init(null, new TrustManager[] { tm }, null); + sslContext.init(null, tmf.getTrustManagers(), null); } @Override diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp index 06abe9d751..0b193f5882 100644 --- a/platform/android/java_glue.cpp +++ b/platform/android/java_glue.cpp @@ -602,23 +602,10 @@ struct TST { TST tst; -struct JAndroidPointerEvent { - - Vector<OS_Android::TouchPos> points; - int pointer; - int what; -}; - -static List<JAndroidPointerEvent> pointer_events; -static List<Ref<InputEvent> > key_events; -static List<OS_Android::JoypadEvent> joy_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 go_back_request = false; static Size2 new_size; static Vector3 accelerometer; static Vector3 magnetometer; @@ -626,8 +613,6 @@ static Vector3 gyroscope; static HashMap<String, JNISingleton *> jni_singletons; static jobject godot_io; -static Vector<int> joy_device_ids; - typedef void (*GFXInitFunc)(void *ud, bool gl2); static jmethodID _on_video_init = 0; @@ -756,7 +741,19 @@ static void _alert(const String &p_message, const String &p_title) { env->CallVoidMethod(_godot_instance, _alertDialog, jStrMessage, jStrTitle); } -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jobject obj, jobject activity, jboolean p_need_reload_hook, jobjectArray p_cmdline, jobject p_asset_manager) { +// volatile because it can be changed from non-main thread and we need to +// ensure the change is immediately visible to other threads. +static volatile int virtual_keyboard_height; + +static int _get_vk_height() { + return virtual_keyboard_height; +} + +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHeight(JNIEnv *env, jobject obj, jint p_height) { + virtual_keyboard_height = p_height; +} + +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jobject obj, jobject activity, jboolean p_need_reload_hook, jobject p_asset_manager, jboolean p_use_apk_expansion) { __android_log_print(ANDROID_LOG_INFO, "godot", "**INIT EVENT! - %p\n", env); @@ -826,36 +823,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en AudioDriverAndroid::setup(gob); } - const char **cmdline = NULL; - int cmdlen = 0; - bool use_apk_expansion = false; - if (p_cmdline) { - cmdlen = env->GetArrayLength(p_cmdline); - if (cmdlen) { - cmdline = (const char **)malloc((env->GetArrayLength(p_cmdline) + 1) * sizeof(const char *)); - cmdline[cmdlen] = NULL; - - for (int i = 0; i < cmdlen; i++) { - - jstring string = (jstring)env->GetObjectArrayElement(p_cmdline, i); - const char *rawString = env->GetStringUTFChars(string, 0); - if (!rawString) { - __android_log_print(ANDROID_LOG_INFO, "godot", "cmdline arg %i is null\n", i); - } else { - //__android_log_print(ANDROID_LOG_INFO,"godot","cmdline arg %i is: %s\n",i,rawString); - - if (strcmp(rawString, "--main_pack") == 0) - use_apk_expansion = true; - } - - cmdline[i] = rawString; - } - } - } - - __android_log_print(ANDROID_LOG_INFO, "godot", "CMDLINE LEN %i - APK EXPANSION %I\n", cmdlen, int(use_apk_expansion)); - - os_android = new OS_Android(_gfx_init_func, env, _open_uri, _get_data_dir, _get_locale, _get_model, _get_screen_dpi, _show_vk, _hide_vk, _set_screen_orient, _get_unique_id, _get_system_dir, _play_video, _is_video_playing, _pause_video, _stop_video, _set_keep_screen_on, _alert, use_apk_expansion); + os_android = new OS_Android(_gfx_init_func, env, _open_uri, _get_data_dir, _get_locale, _get_model, _get_screen_dpi, _show_vk, _hide_vk, _get_vk_height, _set_screen_orient, _get_unique_id, _get_system_dir, _play_video, _is_video_playing, _pause_video, _stop_video, _set_keep_screen_on, _alert, p_use_apk_expansion); os_android->set_need_reload_hooks(p_need_reload_hook); char wd[500]; @@ -864,67 +832,15 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en __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"); - - Error err = Main::setup("apk", cmdlen, (char **)cmdline, false); - - 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 can't be changed - String vd = ProjectSettings::get_singleton()->get("display/driver"); + // String vd = ProjectSettings::get_singleton()->get("display/driver"); 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_org_godotengine_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_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jobject obj, bool p_32_bits) { - - __android_log_print(ANDROID_LOG_INFO, "godot", "^_^_^_^_^ newcontext %lld\n", Thread::get_caller_id()); - - if (os_android) { - os_android->set_context_is_16_bits(!p_32_bits); - } - - if (os_android && step > 0) { - - os_android->reload_gfx(); - } -} - -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jobject obj) { - - input_mutex->lock(); - go_back_request = true; - input_mutex->unlock(); } static void _initialize_java_modules() { - if (!ProjectSettings::get_singleton()->has("android/modules")) { + if (!ProjectSettings::get_singleton()->has_setting("android/modules")) { print_line("ANDROID MODULES: Nothing to load, aborting"); return; } @@ -985,74 +901,114 @@ static void _initialize_java_modules() { } } -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jobject obj) { - +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jobject obj, jobjectArray p_cmdline) { ThreadAndroid::setup_thread(); - //__android_log_print(ANDROID_LOG_INFO,"godot","**STEP EVENT! - %p-%i\n",env,Thread::get_caller_id()); + __android_log_print(ANDROID_LOG_INFO, "godot", "**SETUP"); - 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 + const char **cmdline = NULL; + int cmdlen = 0; + bool use_apk_expansion = false; + if (p_cmdline) { + cmdlen = env->GetArrayLength(p_cmdline); + if (cmdlen) { + cmdline = (const char **)malloc((env->GetArrayLength(p_cmdline) + 1) * sizeof(const char *)); + cmdline[cmdlen] = NULL; - java_class_wrapper = memnew(JavaClassWrapper(_godot_instance)); - ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("JavaClassWrapper", java_class_wrapper)); - _initialize_java_modules(); + for (int i = 0; i < cmdlen; i++) { - // Since Godot is initialized on the UI thread, _main_thread_id was set to that thread's id, - // but for Godot purposes, the main thread is the one running the game loop - Main::setup2(Thread::get_caller_id()); - ++step; - suspend_mutex->unlock(); - input_mutex->unlock(); - return; - }; - if (step == 1) { - if (!Main::start()) { + jstring string = (jstring)env->GetObjectArrayElement(p_cmdline, i); + const char *rawString = env->GetStringUTFChars(string, 0); + if (!rawString) { + __android_log_print(ANDROID_LOG_INFO, "godot", "cmdline arg %i is null\n", i); + } else { + //__android_log_print(ANDROID_LOG_INFO,"godot","cmdline arg %i is: %s\n",i,rawString); - input_mutex->unlock(); - suspend_mutex->lock(); - return; //should exit instead and print the error + if (strcmp(rawString, "-main_pack") == 0) + use_apk_expansion = true; + } + + cmdline[i] = rawString; + } } + } + __android_log_print(ANDROID_LOG_INFO, "godot", "CMDLINE LEN %i - APK EXPANSION %i\n", cmdlen, int(use_apk_expansion)); - os_android->main_loop_begin(); - ++step; +#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", cmdlen, (char **)cmdline, false); +#endif + if (cmdline) { + free(cmdline); } - while (pointer_events.size()) { + 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"); - JAndroidPointerEvent jpe = pointer_events.front()->get(); - os_android->process_touch(jpe.what, jpe.pointer, jpe.points); + java_class_wrapper = memnew(JavaClassWrapper(_godot_instance)); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("JavaClassWrapper", java_class_wrapper)); + _initialize_java_modules(); +} - pointer_events.pop_front(); - } +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jobject obj, jint width, jint height, jboolean reload) { - while (key_events.size()) { + __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)); - Ref<InputEvent> event = key_events.front()->get(); - os_android->process_event(event); + /*input_mutex->lock(); + resized=true; + if (reload) + resized_reload=true; + new_size=Size2(width,height); + input_mutex->unlock();*/ +} - key_events.pop_front(); - }; +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jobject obj, bool p_32_bits) { - while (joy_events.size()) { + __android_log_print(ANDROID_LOG_INFO, "godot", "^_^_^_^_^ newcontext %lld\n", Thread::get_caller_id()); + + if (os_android) { + os_android->set_context_is_16_bits(!p_32_bits); + } - OS_Android::JoypadEvent event = joy_events.front()->get(); - os_android->process_joy_event(event); + if (os_android && step > 0) { - joy_events.pop_front(); + os_android->reload_gfx(); } +} - if (go_back_request) { +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jobject obj) { + os_android->main_loop_request_go_back(); +} - os_android->main_loop_request_go_back(); - go_back_request = false; +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jobject obj) { + if (step == 0) { + __android_log_print(ANDROID_LOG_INFO, "godot", "**FIRST_STEP"); + + // Since Godot is initialized on the UI thread, _main_thread_id was set to that thread's id, + // but for Godot purposes, the main thread is the one running the game loop + Main::setup2(Thread::get_caller_id()); + ++step; + return; + } + + if (step == 1) { + if (!Main::start()) { + return; //should exit instead and print the error + } + + os_android->main_loop_begin(); + ++step; } - input_mutex->unlock(); + //__android_log_print(ANDROID_LOG_INFO,"godot","**STEP EVENT! - %p-%i\n",env,Thread::get_caller_id()); os_android->process_accelerometer(accelerometer); @@ -1067,8 +1023,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, job 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_org_godotengine_godot_GodotLib_touch(JNIEnv *env, jobject obj, jint ev, jint pointer, jint count, jintArray positions) { @@ -1086,16 +1040,8 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch(JNIEnv *env, jo points.push_back(tp); } - JAndroidPointerEvent jpe; - jpe.pointer = pointer; - jpe.points = points; - jpe.what = ev; - - input_mutex->lock(); - - pointer_events.push_back(jpe); + os_android->process_touch(ev, pointer, points); - input_mutex->unlock(); /* if (os_android) os_android->process_touch(ev,pointer,points); @@ -1365,9 +1311,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env jevent.index = p_button; jevent.pressed = p_pressed; - input_mutex->lock(); - joy_events.push_back(jevent); - input_mutex->unlock(); + os_android->process_joy_event(jevent); } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jobject obj, jint p_device, jint p_axis, jfloat p_value) { @@ -1378,9 +1322,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jevent.index = p_axis; jevent.value = p_value; - input_mutex->lock(); - joy_events.push_back(jevent); - input_mutex->unlock(); + os_android->process_joy_event(jevent); } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, jobject obj, jint p_device, jint p_hat_x, jint p_hat_y) { @@ -1401,9 +1343,8 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, j hat |= InputDefault::HAT_MASK_DOWN; } jevent.hat = hat; - input_mutex->lock(); - joy_events.push_back(jevent); - input_mutex->unlock(); + + os_android->process_joy_event(jevent); } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged(JNIEnv *env, jobject obj, jint p_device, jboolean p_connected, jstring p_name) { @@ -1416,6 +1357,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged( JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jobject obj, jint p_scancode, jint p_unicode_char, jboolean p_pressed) { Ref<InputEventKey> ievent; + ievent.instance(); int val = p_unicode_char; int scancode = android_get_keysym(p_scancode); ievent->set_scancode(scancode); @@ -1434,57 +1376,34 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jobj ievent->set_unicode(KEY_ENTER); } else if (p_scancode == 4) { - go_back_request = true; + os_android->main_loop_request_go_back(); } - input_mutex->lock(); - key_events.push_back(ievent); - input_mutex->unlock(); + os_android->process_event(ievent); } JNIEXPORT void JNICALL Java_org_godotengine_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_org_godotengine_godot_GodotLib_magnetometer(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z) { - - input_mutex->lock(); magnetometer = Vector3(x, y, z); - input_mutex->unlock(); } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gyroscope(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z) { - - input_mutex->lock(); gyroscope = Vector3(x, y, z); - input_mutex->unlock(); } JNIEXPORT void JNICALL Java_org_godotengine_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_org_godotengine_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_org_godotengine_godot_GodotLib_audio(JNIEnv *env, jobject obj) { diff --git a/platform/android/java_glue.h b/platform/android/java_glue.h index 64970040f8..0aa2489813 100644 --- a/platform/android/java_glue.h +++ b/platform/android/java_glue.h @@ -36,7 +36,8 @@ #include <jni.h> extern "C" { -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jobject obj, jobject activity, jboolean p_need_reload_hook, jobjectArray p_cmdline, jobject p_asset_manager); +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jobject obj, jobject activity, jboolean p_need_reload_hook, jobject p_asset_manager, jboolean p_use_apk_expansion); +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jobject obj, jobjectArray p_cmdline); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jobject obj, jint width, jint height, jboolean reload); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jobject obj, bool p_32_bits); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jobject obj); @@ -58,6 +59,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_method(JNIEnv *env, j JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getGlobal(JNIEnv *env, jobject obj, jstring path); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *env, jobject p_obj, jint ID, jstring method, jobjectArray params); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *env, jobject p_obj, jint ID, jstring method, jobjectArray params); +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHeight(JNIEnv *env, jobject obj, jint p_height); } #endif diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 1de2608b9e..45df312cae 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -47,6 +47,15 @@ #include "file_access_jandroid.h" #endif +class AndroidLogger : public Logger { +public: + virtual void logv(const char *p_format, va_list p_list, bool p_err) { + __android_log_vprint(p_err ? ANDROID_LOG_ERROR : ANDROID_LOG_INFO, "godot", p_format, p_list); + } + + virtual ~AndroidLogger() {} +}; + int OS_Android::get_video_driver_count() const { return 1; @@ -111,6 +120,15 @@ void OS_Android::initialize_core() { #endif } +void OS_Android::initialize_logger() { + Vector<Logger *> loggers; + loggers.push_back(memnew(AndroidLogger)); + // FIXME: Reenable once we figure out how to get this properly in user:// + // instead of littering the user's working dirs (res:// + pwd) with log files (GH-12277) + //loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); + _set_logger(memnew(CompositeLogger(loggers))); +} + void OS_Android::set_opengl_extensions(const char *p_gl_extensions) { ERR_FAIL_COND(!p_gl_extensions); @@ -137,12 +155,7 @@ void OS_Android::initialize(const VideoMode &p_desired, int p_video_driver, int visual_server->init(); // visual_server->cursor_set_visible(false, 0); - AudioDriverManager::get_driver(p_audio_driver)->set_singleton(); - - if (AudioDriverManager::get_driver(p_audio_driver)->init() != OK) { - - ERR_PRINT("Initializing audio failed."); - } + AudioDriverManager::initialize(p_audio_driver); physics_server = memnew(PhysicsServerSW); physics_server->init(); @@ -167,23 +180,9 @@ void OS_Android::delete_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, const String &p_title) { //print("ALERT: %s\n", p_alert.utf8().get_data()); @@ -522,6 +521,15 @@ bool OS_Android::has_virtual_keyboard() const { return true; } +int OS_Android::get_virtual_keyboard_height() const { + if (get_virtual_keyboard_height_func) { + return get_virtual_keyboard_height_func(); + } + + ERR_PRINT("Cannot obtain virtual keyboard height."); + return 0; +} + void OS_Android::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect) { if (show_virtual_keyboard_func) { @@ -707,7 +715,7 @@ bool OS_Android::_check_internal_feature_support(const String &p_feature) { return p_feature == "mobile" || p_feature == "etc" || p_feature == "etc2"; //TODO support etc2 only if GLES3 driver is selected } -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, GetScreenDPIFunc p_get_screen_dpi_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, SetScreenOrientationFunc p_screen_orient, GetUniqueIDFunc p_get_unique_id, GetSystemDirFunc p_get_sdir_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, AlertFunc p_alert_func, bool p_use_apk_expansion) { +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, GetScreenDPIFunc p_get_screen_dpi_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, VirtualKeyboardHeightFunc p_vk_height_func, SetScreenOrientationFunc p_screen_orient, GetUniqueIDFunc p_get_unique_id, GetSystemDirFunc p_get_sdir_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, AlertFunc p_alert_func, bool p_use_apk_expansion) { use_apk_expansion = p_use_apk_expansion; default_videomode.width = 800; @@ -737,11 +745,14 @@ OS_Android::OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURI show_virtual_keyboard_func = p_show_vk; hide_virtual_keyboard_func = p_hide_vk; + get_virtual_keyboard_height_func = p_vk_height_func; set_screen_orientation_func = p_screen_orient; set_keep_screen_on_func = p_set_keep_screen_on_func; alert_func = p_alert_func; use_reload_hooks = false; + + _set_logger(memnew(AndroidLogger)); } OS_Android::~OS_Android() { diff --git a/platform/android/os_android.h b/platform/android/os_android.h index 119c14bff3..0c78c198a8 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -67,6 +67,7 @@ typedef void (*VideoPauseFunc)(); typedef void (*VideoStopFunc)(); typedef void (*SetKeepScreenOnFunc)(bool p_enabled); typedef void (*AlertFunc)(const String &, const String &); +typedef int (*VirtualKeyboardHeightFunc)(); class OS_Android : public OS_Unix { public: @@ -126,6 +127,7 @@ private: GetScreenDPIFunc get_screen_dpi_func; ShowVirtualKeyboardFunc show_virtual_keyboard_func; HideVirtualKeyboardFunc hide_virtual_keyboard_func; + VirtualKeyboardHeightFunc get_virtual_keyboard_height_func; SetScreenOrientationFunc set_screen_orientation_func; GetUniqueIDFunc get_unique_id_func; GetSystemDirFunc get_system_dir_func; @@ -149,6 +151,7 @@ public: virtual int get_audio_driver_count() const; virtual const char *get_audio_driver_name(int p_driver) const; + virtual void initialize_logger(); virtual void initialize_core(); virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); @@ -161,8 +164,6 @@ public: 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, const String &p_title = "ALERT!"); virtual void set_mouse_show(bool p_show); @@ -202,6 +203,7 @@ public: 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(); + virtual int get_virtual_keyboard_height() const; void set_opengl_extensions(const char *p_gl_extensions); void set_display_size(Size2 p_size); @@ -241,7 +243,7 @@ public: void joy_connection_changed(int p_device, bool p_connected, String p_name); virtual bool _check_internal_feature_support(const String &p_feature); - 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, GetScreenDPIFunc p_get_screen_dpi_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, SetScreenOrientationFunc p_screen_orient, GetUniqueIDFunc p_get_unique_id, GetSystemDirFunc p_get_sdir_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, AlertFunc p_alert_func, bool p_use_apk_expansion); + 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, GetScreenDPIFunc p_get_screen_dpi_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, VirtualKeyboardHeightFunc p_vk_height_func, SetScreenOrientationFunc p_screen_orient, GetUniqueIDFunc p_get_unique_id, GetSystemDirFunc p_get_sdir_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, AlertFunc p_alert_func, bool p_use_apk_expansion); ~OS_Android(); }; diff --git a/platform/android/power_android.cpp b/platform/android/power_android.cpp index 98d4d810b9..48c9377a5a 100644 --- a/platform/android/power_android.cpp +++ b/platform/android/power_android.cpp @@ -198,19 +198,19 @@ bool power_android::GetPowerInfo_Android() { if (Android_JNI_GetPowerInfo(&plugged, &charged, &battery, &this->nsecs_left, &this->percent_left) != -1) { if (plugged) { if (charged) { - this->power_state = POWERSTATE_CHARGED; + this->power_state = OS::POWERSTATE_CHARGED; } else if (battery) { - this->power_state = POWERSTATE_CHARGING; + this->power_state = OS::POWERSTATE_CHARGING; } else { - this->power_state = POWERSTATE_NO_BATTERY; + this->power_state = OS::POWERSTATE_NO_BATTERY; this->nsecs_left = -1; this->percent_left = -1; } } else { - this->power_state = POWERSTATE_ON_BATTERY; + this->power_state = OS::POWERSTATE_ON_BATTERY; } } else { - this->power_state = POWERSTATE_UNKNOWN; + this->power_state = OS::POWERSTATE_UNKNOWN; this->nsecs_left = -1; this->percent_left = -1; } @@ -218,12 +218,12 @@ bool power_android::GetPowerInfo_Android() { return true; } -PowerState power_android::get_power_state() { +OS::PowerState power_android::get_power_state() { if (GetPowerInfo_Android()) { return power_state; } else { WARN_PRINT("Power management is not implemented on this platform, defaulting to POWERSTATE_UNKNOWN"); - return POWERSTATE_UNKNOWN; + return OS::POWERSTATE_UNKNOWN; } } @@ -246,7 +246,7 @@ int power_android::get_power_percent_left() { } power_android::power_android() - : nsecs_left(-1), percent_left(-1), power_state(POWERSTATE_UNKNOWN) { + : nsecs_left(-1), percent_left(-1), power_state(OS::POWERSTATE_UNKNOWN) { } power_android::~power_android() { diff --git a/platform/android/power_android.h b/platform/android/power_android.h index fc618c660d..4c7af1c771 100644 --- a/platform/android/power_android.h +++ b/platform/android/power_android.h @@ -31,7 +31,7 @@ #ifndef PLATFORM_ANDROID_POWER_ANDROID_H_ #define PLATFORM_ANDROID_POWER_ANDROID_H_ -#include "os/power.h" +#include "os/os.h" #include <android/native_window_jni.h> class power_android { @@ -57,7 +57,7 @@ private: int nsecs_left; int percent_left; - PowerState power_state; + OS::PowerState power_state; bool GetPowerInfo_Android(); bool UpdatePowerInfo(); @@ -71,7 +71,7 @@ public: static struct LocalReferenceHolder LocalReferenceHolder_Setup(const char *func); static void LocalReferenceHolder_Cleanup(struct LocalReferenceHolder *refholder); - PowerState get_power_state(); + OS::PowerState get_power_state(); int get_power_seconds_left(); int get_power_percent_left(); }; |