diff options
Diffstat (limited to 'platform/android')
76 files changed, 2194 insertions, 1370 deletions
diff --git a/platform/android/AndroidManifest.xml.template b/platform/android/AndroidManifest.xml.template index 37dee4a9a5..2a24c7cdc2 100644 --- a/platform/android/AndroidManifest.xml.template +++ b/platform/android/AndroidManifest.xml.template @@ -7,7 +7,7 @@ > <supports-screens android:smallScreens="true" android:normalScreens="true" - android:largeScreens="false" + android:largeScreens="true" android:xlargeScreens="true"/> <application android:label="@string/godot_project_name_string" android:icon="@drawable/icon" android:allowBackup="false" $$ADD_APPATTRIBUTE_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="19"/> +<uses-sdk android:minSdkVersion="10" android:targetSdkVersion="23"/> </manifest> diff --git a/platform/android/SCsub b/platform/android/SCsub index c8feac8690..146f7c25a3 100644 --- a/platform/android/SCsub +++ b/platform/android/SCsub @@ -1,106 +1,132 @@ +#!/usr/bin/env python + import shutil Import('env') android_files = [ - 'os_android.cpp', - 'godot_android.cpp', - 'file_access_android.cpp', - 'dir_access_android.cpp', - 'audio_driver_opensl.cpp', - 'file_access_jandroid.cpp', - 'dir_access_jandroid.cpp', - 'thread_jandroid.cpp', - 'audio_driver_jandroid.cpp', - 'ifaddrs_android.cpp', - 'android_native_app_glue.c', - 'java_glue.cpp', - 'cpu-features.c', - 'java_class_wrapper.cpp' + 'os_android.cpp', + 'godot_android.cpp', + 'file_access_android.cpp', + 'dir_access_android.cpp', + 'audio_driver_opensl.cpp', + 'file_access_jandroid.cpp', + 'dir_access_jandroid.cpp', + 'thread_jandroid.cpp', + 'audio_driver_jandroid.cpp', + 'ifaddrs_android.cpp', + 'android_native_app_glue.c', + 'java_glue.cpp', + 'cpu-features.c', + 'java_class_wrapper.cpp' ] -#env.Depends('#core/math/vector3.h', 'vector3_psp.h') +# 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']) + env_android.Append(CPPFLAGS=['-DPROFILER_ENABLED']) -android_objects=[] +android_objects = [] for x in android_files: - android_objects.append( env_android.SharedObject( x ) ) + android_objects.append(env_android.SharedObject(x)) prog = None -abspath=env.Dir(".").abspath +abspath = env.Dir(".").abspath -gradle_basein = open(abspath+"/build.gradle.template","rb") -gradle_baseout = open(abspath+"/java/build.gradle","wb") +gradle_basein = open(abspath + "/build.gradle.template", "rb") +gradle_baseout = open(abspath + "/java/build.gradle", "wb") gradle_text = gradle_basein.read() -gradle_maven_repos_text="" +gradle_maven_repos_text = "" if len(env.android_maven_repos) > 0: - gradle_maven_repos_text+="maven {\n" - for x in env.android_maven_repos: - gradle_maven_repos_text+="\t\t"+x+"\n" - gradle_maven_repos_text+="\t}\n" + gradle_maven_repos_text += "maven {\n" + for x in env.android_maven_repos: + gradle_maven_repos_text += "\t\t" + x + "\n" + gradle_maven_repos_text += "\t}\n" -gradle_maven_dependencies_text="" +gradle_maven_dependencies_text = "" for x in env.android_dependencies: - gradle_maven_dependencies_text+=x+"\n" + gradle_maven_dependencies_text += x + "\n" -gradle_java_dirs_text="" +gradle_java_dirs_text = "" for x in env.android_java_dirs: - gradle_java_dirs_text+=",'"+x.replace("\\","/")+"'" + gradle_java_dirs_text += ",'" + x.replace("\\", "/") + "'" -gradle_res_dirs_text="" +gradle_res_dirs_text = "" for x in env.android_res_dirs: - gradle_res_dirs_text+=",'"+x.replace("\\","/")+"'" + gradle_res_dirs_text += ",'" + x.replace("\\", "/") + "'" -gradle_aidl_dirs_text="" +gradle_aidl_dirs_text = "" for x in env.android_aidl_dirs: - gradle_aidl_dirs_text+=",'"+x.replace("\\","/")+"'" + gradle_aidl_dirs_text += ",'" + x.replace("\\", "/") + "'" -gradle_jni_dirs_text="" +gradle_jni_dirs_text = "" for x in env.android_jni_dirs: - gradle_jni_dirs_text+=",'"+x.replace("\\","/")+"'" + gradle_jni_dirs_text += ",'" + x.replace("\\", "/") + "'" + +gradle_asset_dirs_text = "" + +gradle_default_config_text = "" -gradle_asset_dirs_text="" +for x in env.android_default_config: + gradle_default_config_text += x + "\n\t\t" -gradle_text = gradle_text.replace("$$GRADLE_REPOSITORY_URLS$$",gradle_maven_repos_text) -gradle_text = gradle_text.replace("$$GRADLE_DEPENDENCIES$$",gradle_maven_dependencies_text) -gradle_text = gradle_text.replace("$$GRADLE_JAVA_DIRS$$",gradle_java_dirs_text) -gradle_text = gradle_text.replace("$$GRADLE_RES_DIRS$$",gradle_res_dirs_text) -gradle_text = gradle_text.replace("$$GRADLE_ASSET_DIRS$$",gradle_asset_dirs_text) -gradle_text = gradle_text.replace("$$GRADLE_AIDL_DIRS$$",gradle_aidl_dirs_text) -gradle_text = gradle_text.replace("$$GRADLE_JNI_DIRS$$",gradle_jni_dirs_text) +gradle_text = gradle_text.replace("$$GRADLE_REPOSITORY_URLS$$", gradle_maven_repos_text) +gradle_text = gradle_text.replace("$$GRADLE_DEPENDENCIES$$", gradle_maven_dependencies_text) +gradle_text = gradle_text.replace("$$GRADLE_JAVA_DIRS$$", gradle_java_dirs_text) +gradle_text = gradle_text.replace("$$GRADLE_RES_DIRS$$", gradle_res_dirs_text) +gradle_text = gradle_text.replace("$$GRADLE_ASSET_DIRS$$", gradle_asset_dirs_text) +gradle_text = gradle_text.replace("$$GRADLE_AIDL_DIRS$$", gradle_aidl_dirs_text) +gradle_text = gradle_text.replace("$$GRADLE_JNI_DIRS$$", gradle_jni_dirs_text) +gradle_text = gradle_text.replace("$$GRADLE_DEFAULT_CONFIG$$", gradle_default_config_text) -gradle_baseout.write( gradle_text ) +gradle_baseout.write(gradle_text) gradle_baseout.close() -pp_basein = open(abspath+"/AndroidManifest.xml.template","rb") -pp_baseout = open(abspath+"/java/AndroidManifest.xml","wb") +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) -manifest = manifest.replace("$$ADD_PERMISSION_CHUNKS$$",env.android_permission_chunk) -manifest = manifest.replace("$$ADD_APPATTRIBUTE_CHUNKS$$",env.android_appattributes_chunk) -pp_baseout.write( manifest ) +manifest = manifest.replace("$$ADD_APPLICATION_CHUNKS$$", env.android_manifest_chunk) +manifest = manifest.replace("$$ADD_PERMISSION_CHUNKS$$", env.android_permission_chunk) +manifest = manifest.replace("$$ADD_APPATTRIBUTE_CHUNKS$$", env.android_appattributes_chunk) +pp_baseout.write(manifest) + + +env_android.SharedLibrary("#bin/libgodot", [android_objects], SHLIBSUFFIX=env["SHLIBSUFFIX"]) + +lib_arch_dir = '' +if env['android_arch'] == 'armv6': + lib_arch_dir = 'armeabi' +elif env['android_arch'] == 'armv7': + lib_arch_dir = 'armeabi-v7a' +elif env['android_arch'] == 'x86': + lib_arch_dir = 'x86' +else: + print 'WARN: Architecture not suitable for embedding into APK; keeping .so at \\bin' -env_android.SharedLibrary("#bin/libgodot",[android_objects],SHLIBSUFFIX=env["SHLIBSUFFIX"]) +if lib_arch_dir != '': + if env['target'] == 'release': + lib_type_dir = 'release' + else: # release_debug, debug + lib_type_dir = 'debug' -#env.Command('#bin/libgodot_android.so', '#platform/android/libgodot_android.so', Copy('bin/libgodot_android.so', 'platform/android/libgodot_android.so')) + out_dir = '#platform/android/java/libs/' + lib_type_dir + '/' + lib_arch_dir + env_android.Command(out_dir + '/libgodot_android.so', '#bin/libgodot' + env['SHLIBSUFFIX'], Move("$TARGET", "$SOURCE")) diff --git a/platform/android/android_native_app_glue.h b/platform/android/android_native_app_glue.h index 3e7a4ea7a0..36278d4c66 100644 --- a/platform/android/android_native_app_glue.h +++ b/platform/android/android_native_app_glue.h @@ -1,32 +1,5 @@ -/*************************************************************************/ -/* android_native_app_glue.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2016 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 +/* + * 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. diff --git a/platform/android/audio_driver_jandroid.cpp b/platform/android/audio_driver_jandroid.cpp index 6d428e3fe5..d9e40a5913 100644 --- a/platform/android/audio_driver_jandroid.cpp +++ b/platform/android/audio_driver_jandroid.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 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 */ @@ -71,7 +71,7 @@ Error AudioDriverAndroid::init(){ } */ -// Android_JNI_SetupThread(); + //Android_JNI_SetupThread(); // __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device"); @@ -192,29 +192,31 @@ void AudioDriverAndroid::thread_func(JNIEnv *env) { 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(); @@ -236,13 +238,11 @@ void AudioDriverAndroid::set_pause(bool p_pause) { } -AudioDriverAndroid::AudioDriverAndroid() -{ +AudioDriverAndroid::AudioDriverAndroid() { + s_ad=this; active=false; - - } #endif diff --git a/platform/android/audio_driver_jandroid.h b/platform/android/audio_driver_jandroid.h index f79057efe5..01ce31be8f 100644 --- a/platform/android/audio_driver_jandroid.h +++ b/platform/android/audio_driver_jandroid.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 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 */ diff --git a/platform/android/audio_driver_opensl.cpp b/platform/android/audio_driver_opensl.cpp index a908f6193e..7aec2b174e 100644 --- a/platform/android/audio_driver_opensl.cpp +++ b/platform/android/audio_driver_opensl.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 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 */ @@ -108,7 +108,7 @@ void AudioDriverOpenSL::_buffer_callbacks( AudioDriverOpenSL *ad = (AudioDriverOpenSL*)pContext; -// ad->_buffer_callback(queueItf,eventFlags,pBuffer,bufferSize,dataUsed); + //ad->_buffer_callback(queueItf,eventFlags,pBuffer,bufferSize,dataUsed); ad->_buffer_callback(queueItf); } @@ -207,6 +207,7 @@ Error AudioDriverOpenSL::init(){ return OK; } + void AudioDriverOpenSL::start(){ @@ -270,8 +271,8 @@ void AudioDriverOpenSL::start(){ 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 */ + //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; @@ -294,7 +295,7 @@ void AudioDriverOpenSL::start(){ audioSink.pLocator = (void *)&locator_outputmix; audioSink.pFormat = NULL; /* Initialize the context for Buffer queue callbacks */ -// cntxt.pDataBase = (void*)&pcmData; + //cntxt.pDataBase = (void*)&pcmData; //cntxt.pData = cntxt.pDataBase; //cntxt.size = sizeof(pcmData); /* Set arrays required[] and iidArray[] for SEEK interface @@ -366,26 +367,31 @@ void AudioDriverOpenSL::start(){ active=true; } + int AudioDriverOpenSL::get_mix_rate() const { return 44100; } + AudioDriverSW::OutputFormat AudioDriverOpenSL::get_output_format() const{ return OUTPUT_STEREO; } + void AudioDriverOpenSL::lock(){ if (active && mutex) mutex->lock(); } + void AudioDriverOpenSL::unlock() { if (active && mutex) mutex->unlock(); } + void AudioDriverOpenSL::finish(){ (*sl)->Destroy(sl); diff --git a/platform/android/audio_driver_opensl.h b/platform/android/audio_driver_opensl.h index 1b04f32fd2..8839d20bab 100644 --- a/platform/android/audio_driver_opensl.h +++ b/platform/android/audio_driver_opensl.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 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 */ diff --git a/platform/android/build.gradle.template b/platform/android/build.gradle.template index 9461cd2e99..873eef0566 100644 --- a/platform/android/build.gradle.template +++ b/platform/android/build.gradle.template @@ -3,7 +3,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:1.2.0' + classpath 'com.android.tools.build:gradle:2.1.0' } } @@ -17,18 +17,20 @@ allprojects { } dependencies { - - $$GRADLE_DEPENDENCIES$$ + compile 'com.android.support:support-v4:23.+' // can be removed if minSdkVersion 16 and modify DownloadNotification.java & V14CustomNotification.java + $$GRADLE_DEPENDENCIES$$ } android { lintOptions { abortOnError false + disable 'MissingTranslation' } - compileSdkVersion 19 - buildToolsVersion "19.1" + compileSdkVersion 23 + buildToolsVersion "23.0.3" + useLibrary 'org.apache.http.legacy' packagingOptions { exclude 'META-INF/LICENSE' @@ -36,35 +38,49 @@ android { } defaultConfig { minSdkVersion 14 - targetSdkVersion 19 + targetSdkVersion 23 + $$GRADLE_DEFAULT_CONFIG$$ + } + // Both signing and zip-aligning will be done at export time + buildTypes.all { buildType -> + buildType.zipAlignEnabled false + buildType.signingConfig null } sourceSets { main { manifest.srcFile 'AndroidManifest.xml' java.srcDirs = ['src' - $$GRADLE_JAVA_DIRS$$ + $$GRADLE_JAVA_DIRS$$ ] resources.srcDirs = [ 'res' - $$GRADLE_RES_DIRS$$ + $$GRADLE_RES_DIRS$$ ] res.srcDirs = ['res'] // libs.srcDirs = ['libs'] aidl.srcDirs = [ 'aidl' - $$GRADLE_AIDL_DIRS$$ + $$GRADLE_AIDL_DIRS$$ ] assets.srcDirs = [ 'assets' - $$GRADLE_ASSET_DIRS$$ + $$GRADLE_ASSET_DIRS$$ ] jniLibs.srcDirs = [ - 'libs' - $$GRADLE_JNI_DIRS$$ - ] + $$GRADLE_JNI_DIRS$$ + ] } - + debug.jniLibs.srcDirs = [ + 'libs/debug' + $$GRADLE_JNI_DIRS$$ + ] + release.jniLibs.srcDirs = [ + 'libs/release' + $$GRADLE_JNI_DIRS$$ + ] + } + applicationVariants.all { variant -> + // ApplicationVariant is undocumented, but this method is widely used; may break with another version of the Android Gradle plugin + variant.outputs.get(0).setOutputFile(new File("${projectDir}/../../../bin", "android_${variant.name}.apk")) } - - } diff --git a/platform/android/detect.py b/platform/android/detect.py index 11b14eb989..d1073e0c7b 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -3,248 +3,263 @@ import sys import string import platform + def is_active(): - return True + return True + def get_name(): - return "Android" + return "Android" + def can_build(): - import os - if (not os.environ.has_key("ANDROID_NDK_ROOT")): - return False + import os + if (not os.environ.has_key("ANDROID_NDK_ROOT")): + return False + + return True - return True def get_opts(): - return [ - ('ANDROID_NDK_ROOT', 'the path to Android NDK', os.environ.get("ANDROID_NDK_ROOT", 0)), - ('NDK_TARGET', 'toolchain to use for the NDK',os.environ.get("NDK_TARGET", "arm-linux-androideabi-4.9")), - ('NDK_TARGET_X86', 'toolchain to use for the NDK x86',os.environ.get("NDK_TARGET_X86", "x86-4.9")), - ('ndk_platform', 'compile for platform: (android-<api> , example: android-15)',"android-15"), - ('android_arch', 'select compiler architecture: (armv7/armv6/x86)',"armv7"), - ('android_neon','enable neon (armv7 only)',"yes"), - ('android_stl','enable STL support in android port (for modules)',"no") - ] + return [ + ('ANDROID_NDK_ROOT', 'the path to Android NDK', + os.environ.get("ANDROID_NDK_ROOT", 0)), + ('ndk_platform', 'compile for platform: (android-<api> , example: android-14)', "android-14"), + ('android_arch', 'select compiler architecture: (armv7/armv6/x86)', "armv7"), + ('android_neon', 'enable neon (armv7 only)', "yes"), + ('android_stl', 'enable STL support in android port (for modules)', "no") + ] def get_flags(): - return [ - ('tools', 'no'), - ('nedmalloc', 'no'), - ('builtin_zlib', 'no'), - ('openssl','builtin'), #use builtin openssl - ] + return [ + ('tools', '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); + 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): - # Workaround for MinGW. See: - # http://www.scons.org/wiki/LongCmdLinesOnWin32 - import os - if (os.name=="nt"): - - import subprocess - - def mySubProcess(cmdline,env): - #print "SPAWNED : " + cmdline - startupinfo = subprocess.STARTUPINFO() - startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW - proc = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, startupinfo=startupinfo, shell = False, env = env) - data, err = proc.communicate() - rv = proc.wait() - if rv: - print "=====" - print err - print "=====" - return rv - - def mySpawn(sh, escape, cmd, args, env): - - newargs = ' '.join(args[1:]) - cmdline = cmd + " " + newargs - - rv=0 - if len(cmdline) > 32000 and cmd.endswith("ar") : - cmdline = cmd + " " + args[1] + " " + args[2] + " " - for i in range(3,len(args)) : - rv = mySubProcess( cmdline + args[i], env ) - if rv : - break - else: - rv = mySubProcess( cmdline, env ) - - return rv - - env['SPAWN'] = mySpawn - - ndk_platform=env['ndk_platform'] - - if env['android_arch'] not in ['armv7','armv6','x86']: - env['android_arch']='armv7' - - if env['android_arch']=='x86': - env['NDK_TARGET']=env['NDK_TARGET_X86'] - env["x86_opt_gcc"]=True - - if env['PLATFORM'] == 'win32': - env.Tool('gcc') - env['SHLIBSUFFIX'] = '.so' - - - neon_text="" - if env["android_arch"]=="armv7" and env['android_neon']=='yes': - neon_text=" (with neon)" - print("Godot Android!!!!! ("+env['android_arch']+")"+neon_text) - - env.Append(CPPPATH=['#platform/android']) - - if env['android_arch']=='x86': - env.extra_suffix=".x86"+env.extra_suffix - elif env['android_arch']=='armv6': - env.extra_suffix=".armv6"+env.extra_suffix - elif env["android_arch"]=="armv7": - if env['android_neon']=='yes': - env.extra_suffix=".armv7.neon"+env.extra_suffix - else: - env.extra_suffix=".armv7"+env.extra_suffix - - gcc_path=env["ANDROID_NDK_ROOT"]+"/toolchains/"+env["NDK_TARGET"]+"/prebuilt/"; - - 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' - env['SHLIBSUFFIX'] = '.so' - elif (os.name=="nt"): - gcc_path=gcc_path+"/windows-x86_64/bin" #this may be wrong - - - - env['ENV']['PATH'] = gcc_path+":"+env['ENV']['PATH'] - if env['android_arch']=='x86': - env['CC'] = gcc_path+'/i686-linux-android-gcc' - env['CXX'] = gcc_path+'/i686-linux-android-g++' - env['AR'] = gcc_path+"/i686-linux-android-ar" - env['RANLIB'] = gcc_path+"/i686-linux-android-ranlib" - env['AS'] = gcc_path+"/i686-linux-android-as" - else: - 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" - - if env['android_arch']=='x86': - env['ARCH'] = 'arch-x86' - else: - env['ARCH'] = 'arch-arm' - - import string - #include path - gcc_include=env["ANDROID_NDK_ROOT"]+"/platforms/"+ndk_platform+"/"+env['ARCH'] +"/usr/include" - ld_sysroot=env["ANDROID_NDK_ROOT"]+"/platforms/"+ndk_platform+"/"+env['ARCH'] - #glue_include=env["ANDROID_NDK_ROOT"]+"/sources/android/native_app_glue" - ld_path=env["ANDROID_NDK_ROOT"]+"/platforms/"+ndk_platform+"/"+env['ARCH']+"/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 ') - - env['neon_enabled']=False - if env['android_arch']=='x86': - env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -fvisibility=hidden -D__GLIBC__ -Wno-psabi -ftree-vectorize -funsafe-math-optimizations -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED') - elif env["android_arch"]=="armv6": - env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -fvisibility=hidden -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') - elif env["android_arch"]=="armv7": - env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -fvisibility=hidden -D__ARM_ARCH_7__ -D__ARM_ARCH_7A__ -D__GLIBC__ -Wno-psabi -march=armv7-a -mfloat-abi=softfp -ftree-vectorize -funsafe-math-optimizations -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED') - if env['android_neon']=='yes': - env['neon_enabled']=True - env.Append(CCFLAGS=['-mfpu=neon','-D__ARM_NEON__']) - else: - env.Append(CCFLAGS=['-mfpu=vfpv3-d16']) - - env.Append(LDPATH=[ld_path]) - env.Append(LIBS=['OpenSLES']) -# env.Append(LIBS=['c','m','stdc++','log','EGL','GLESv1_CM','GLESv2','OpenSLES','supc++','android']) - 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']) - - elif (env["target"]=="release_debug"): - - env.Append(CCFLAGS=['-O2', '-ffast-math','-DDEBUG_ENABLED']) - - elif (env["target"]=="debug"): - - env.Append(CCFLAGS=['-D_DEBUG', '-g1', '-Wall', '-O0', '-DDEBUG_ENABLED']) - env.Append(CPPFLAGS=['-DDEBUG_MEMORY_ALLOC']) - - env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED', '-DNO_FCNTL','-DMPC_FIXED_POINT']) -# env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED','-DMPC_FIXED_POINT']) - - if(env["opus"]=="yes"): - if (env["android_arch"]=="armv6" or env["android_arch"]=="armv7"): - env.Append(CFLAGS=["-DOPUS_ARM_OPT"]) - env.opus_fixed_point="yes" - - 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.8/include"]) - if env['android_arch']=='x86': - env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.8/libs/x86/include"]) - env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.8/libs/x86"]) - elif env['android_arch']=='armv6': - env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi/include"]) - env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi"]) - elif env["android_arch"]=="armv7": - env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi-v7a/include"]) - env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi-v7a"]) - - 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/gnu-libstdc++/4.9/include"]) - env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cpufeatures"]) - if env['android_arch']=='x86': - env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.9/libs/x86"]) - elif env["android_arch"]=="armv6": - env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.9/libs/armeabi"]) - elif env["android_arch"]=="armv7": - env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.9/libs/armeabi-v7a"]) - env.Append(LIBS=['gnustl_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') } ) - - env.use_windows_spawn_fix() + # Workaround for MinGW. See: + # http://www.scons.org/wiki/LongCmdLinesOnWin32 + import os + if (os.name == "nt"): + + import subprocess + + def mySubProcess(cmdline, env): + # print "SPAWNED : " + cmdline + startupinfo = subprocess.STARTUPINFO() + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW + proc = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, startupinfo=startupinfo, shell=False, env=env) + data, err = proc.communicate() + rv = proc.wait() + if rv: + print "=====" + print err + print "=====" + return rv + + def mySpawn(sh, escape, cmd, args, env): + + newargs = ' '.join(args[1:]) + cmdline = cmd + " " + newargs + + rv = 0 + if len(cmdline) > 32000 and cmd.endswith("ar"): + cmdline = cmd + " " + args[1] + " " + args[2] + " " + for i in range(3, len(args)): + rv = mySubProcess(cmdline + args[i], env) + if rv: + break + else: + rv = mySubProcess(cmdline, env) + + return rv + + env['SPAWN'] = mySpawn + + ndk_platform = env['ndk_platform'] + + if env['android_arch'] not in ['armv7', 'armv6', 'x86']: + env['android_arch'] = 'armv7' + + if env['android_arch'] == 'x86': + env["x86_libtheora_opt_gcc"] = True + + if env['PLATFORM'] == 'win32': + env.Tool('gcc') + env['SHLIBSUFFIX'] = '.so' + + neon_text = "" + if env["android_arch"] == "armv7" and env['android_neon'] == 'yes': + neon_text = " (with neon)" + print("Godot Android!!!!! (" + env['android_arch'] + ")" + neon_text) + + env.Append(CPPPATH=['#platform/android']) + + if env['android_arch'] == 'x86': + env.extra_suffix = ".x86" + env.extra_suffix + target_subpath = "x86-4.9" + abi_subpath = "i686-linux-android" + arch_subpath = "x86" + elif env['android_arch'] == 'armv6': + env.extra_suffix = ".armv6" + env.extra_suffix + target_subpath = "arm-linux-androideabi-4.9" + abi_subpath = "arm-linux-androideabi" + arch_subpath = "armeabi" + elif env["android_arch"] == "armv7": + target_subpath = "arm-linux-androideabi-4.9" + abi_subpath = "arm-linux-androideabi" + arch_subpath = "armeabi-v7a" + if env['android_neon'] == 'yes': + env.extra_suffix = ".armv7.neon" + env.extra_suffix + else: + env.extra_suffix = ".armv7" + env.extra_suffix + + mt_link = True + if (sys.platform.startswith("linux")): + host_subpath = "linux-x86_64" + elif (sys.platform.startswith("darwin")): + host_subpath = "darwin-x86_64" + elif (sys.platform.startswith('win')): + if (platform.machine().endswith('64')): + host_subpath = "windows-x86_64" + else: + mt_link = False + host_subpath = "windows" + + compiler_path = env["ANDROID_NDK_ROOT"] + \ + "/toolchains/llvm/prebuilt/" + host_subpath + "/bin" + gcc_toolchain_path = env["ANDROID_NDK_ROOT"] + \ + "/toolchains/" + target_subpath + "/prebuilt/" + host_subpath + tools_path = gcc_toolchain_path + "/" + abi_subpath + "/bin" + + # For Clang to find NDK tools in preference of those system-wide + env.PrependENVPath('PATH', tools_path) + + env['CC'] = compiler_path + '/clang' + env['CXX'] = compiler_path + '/clang++' + env['AR'] = tools_path + "/ar" + env['RANLIB'] = tools_path + "/ranlib" + env['AS'] = tools_path + "/as" + + if env['android_arch'] == 'x86': + env['ARCH'] = 'arch-x86' + else: + env['ARCH'] = 'arch-arm' + + sysroot = env["ANDROID_NDK_ROOT"] + \ + "/platforms/" + ndk_platform + "/" + env['ARCH'] + common_opts = ['-fno-integrated-as', '-gcc-toolchain', gcc_toolchain_path] + + env.Append(CPPFLAGS=["-isystem", sysroot + "/usr/include"]) + env.Append(CPPFLAGS=string.split( + '-Wno-invalid-command-line-argument -Wno-unused-command-line-argument')) + env.Append(CPPFLAGS=string.split( + '-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden -fno-strict-aliasing -Wa,--noexecstack')) + env.Append(CPPFLAGS=string.split('-DANDROID -DNO_STATVFS -DGLES2_ENABLED')) + + env['neon_enabled'] = False + if env['android_arch'] == 'x86': + can_vectorize = True + target_opts = ['-target', 'i686-none-linux-android'] + elif env["android_arch"] == "armv6": + can_vectorize = False + target_opts = ['-target', 'armv6-none-linux-androideabi'] + env.Append(CPPFLAGS=string.split( + '-D__ARM_ARCH_6__ -march=armv6 -mfpu=vfp -mfloat-abi=softfp')) + elif env["android_arch"] == "armv7": + can_vectorize = True + target_opts = ['-target', 'armv7-none-linux-androideabi'] + env.Append(CPPFLAGS=string.split( + '-D__ARM_ARCH_7__ -D__ARM_ARCH_7A__ -march=armv7-a -mfloat-abi=softfp')) + if env['android_neon'] == 'yes': + env['neon_enabled'] = True + env.Append(CPPFLAGS=['-mfpu=neon', '-D__ARM_NEON__']) + else: + env.Append(CPPFLAGS=['-mfpu=vfpv3-d16']) + + env.Append(CPPFLAGS=target_opts) + env.Append(CPPFLAGS=common_opts) + + env.Append(LIBS=['OpenSLES']) + env.Append(LIBS=['EGL', 'OpenSLES', 'android']) + env.Append(LIBS=['log', 'GLESv1_CM', 'GLESv2', 'z']) + + if (sys.platform.startswith("darwin")): + env['SHLIBSUFFIX'] = '.so' + + env['LINKFLAGS'] = ['-shared', '--sysroot=' + + sysroot, '-Wl,--warn-shared-textrel'] + env.Append(LINKFLAGS=string.split( + '-Wl,--fix-cortex-a8')) + env.Append(LINKFLAGS=string.split( + '-Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now')) + env.Append(LINKFLAGS=string.split( + '-Wl,-soname,libgodot_android.so -Wl,--gc-sections')) + if mt_link: + env.Append(LINKFLAGS=['-Wl,--threads']) + env.Append(LINKFLAGS=target_opts) + env.Append(LINKFLAGS=common_opts) + + env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"] + '/toolchains/arm-linux-androideabi-4.9/prebuilt/' + + host_subpath + '/lib/gcc/' + abi_subpath + '/4.9.x']) + env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"] + + '/toolchains/arm-linux-androideabi-4.9/prebuilt/' + host_subpath + '/' + abi_subpath + '/lib']) + + if (env["target"].startswith("release")): + env.Append(LINKFLAGS=['-O2']) + env.Append(CPPFLAGS=['-O2', '-DNDEBUG', '-ffast-math', + '-funsafe-math-optimizations', '-fomit-frame-pointer']) + if (can_vectorize): + env.Append(CPPFLAGS=['-ftree-vectorize']) + if (env["target"] == "release_debug"): + env.Append(CPPFLAGS=['-DDEBUG_ENABLED']) + elif (env["target"] == "debug"): + env.Append(LINKFLAGS=['-O0']) + env.Append(CPPFLAGS=['-O0', '-D_DEBUG', '-UNDEBUG', '-DDEBUG_ENABLED', + '-DDEBUG_MEMORY_ALLOC', '-g', '-fno-limit-debug-info']) + + env.Append(CPPFLAGS=['-DANDROID_ENABLED', + '-DUNIX_ENABLED', '-DNO_FCNTL', '-DMPC_FIXED_POINT']) + + # TODO: Move that to opus module's config + if("module_opus_enabled" in env and env["module_opus_enabled"] != "no"): + if (env["android_arch"] == "armv6" or env["android_arch"] == "armv7"): + env.Append(CFLAGS=["-DOPUS_ARM_OPT"]) + env.opus_fixed_point = "yes" + + if (env['android_stl'] == 'yes'): + 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]) + env.Append(LIBS=["gnustl_static"]) + else: + env.Append(CXXFLAGS=['-fno-rtti', '-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')}) + + env.use_windows_spawn_fix() diff --git a/platform/android/dir_access_android.cpp b/platform/android/dir_access_android.cpp index 85df5dc37a..42ac34a589 100644 --- a/platform/android/dir_access_android.cpp +++ b/platform/android/dir_access_android.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 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 */ @@ -37,16 +37,16 @@ DirAccess *DirAccessAndroid::create_fs() { return memnew(DirAccessAndroid); } -bool DirAccessAndroid::list_dir_begin() { +Error 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 ERR_CANT_OPEN; //nothing - return false; + return OK; } String DirAccessAndroid::get_next(){ @@ -61,6 +61,7 @@ String DirAccessAndroid::get_next(){ } + bool DirAccessAndroid::current_is_dir() const{ String sd; @@ -79,9 +80,11 @@ bool DirAccessAndroid::current_is_dir() const{ return false; } + bool DirAccessAndroid::current_is_hidden() const{ return current!="." && current!=".." && current.begins_with("."); } + void DirAccessAndroid::list_dir_end(){ if (aad==NULL) @@ -96,6 +99,7 @@ int DirAccessAndroid::get_drive_count(){ return 0; } + String DirAccessAndroid::get_drive(int p_drive){ return ""; @@ -164,6 +168,7 @@ 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); diff --git a/platform/android/dir_access_android.h b/platform/android/dir_access_android.h index 9477ca48fd..72611ceb59 100644 --- a/platform/android/dir_access_android.h +++ b/platform/android/dir_access_android.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 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 */ @@ -49,7 +49,7 @@ class DirAccessAndroid : public DirAccess { public: - virtual bool list_dir_begin(); ///< This starts dir listing + virtual Error list_dir_begin(); ///< This starts dir listing virtual String get_next(); virtual bool current_is_dir() const; virtual bool current_is_hidden() const; diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp index 8b7cb992d9..2528b18248 100644 --- a/platform/android/dir_access_jandroid.cpp +++ b/platform/android/dir_access_jandroid.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 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 */ @@ -47,7 +47,7 @@ DirAccess *DirAccessJAndroid::create_fs() { return memnew(DirAccessJAndroid); } -bool DirAccessJAndroid::list_dir_begin() { +Error DirAccessJAndroid::list_dir_begin() { list_dir_end(); JNIEnv *env = ThreadAndroid::get_env(); @@ -55,11 +55,11 @@ bool DirAccessJAndroid::list_dir_begin() { jstring js = env->NewStringUTF(current_dir.utf8().get_data()); int res = env->CallIntMethod(io,_dir_open,js); if (res<=0) - return true; + return ERR_CANT_OPEN; id=res; - return false; + return OK; } String DirAccessJAndroid::get_next(){ @@ -76,6 +76,7 @@ String DirAccessJAndroid::get_next(){ return ret; } + bool DirAccessJAndroid::current_is_dir() const{ @@ -106,6 +107,7 @@ int DirAccessJAndroid::get_drive_count(){ return 0; } + String DirAccessJAndroid::get_drive(int p_drive){ return ""; @@ -152,7 +154,7 @@ Error DirAccessJAndroid::change_dir(String p_dir){ String DirAccessJAndroid::get_current_dir(){ - return "/"+current_dir; + return "res://"+current_dir; } bool DirAccessJAndroid::file_exists(String p_file){ @@ -201,7 +203,6 @@ bool DirAccessJAndroid::dir_exists(String p_dir) { return false; env->CallVoidMethod(io,_dir_close,res); - env->DeleteLocalRef(js); return true; } @@ -215,6 +216,7 @@ 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); @@ -255,7 +257,7 @@ void DirAccessJAndroid::setup( jobject p_io) { __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _dir_is_dir ok!!"); } -// (*env)->CallVoidMethod(env,obj,aMethodID, myvar); + //(*env)->CallVoidMethod(env,obj,aMethodID, myvar); } @@ -266,6 +268,6 @@ DirAccessJAndroid::DirAccessJAndroid() { DirAccessJAndroid::~DirAccessJAndroid() { - list_dir_end();; + list_dir_end(); } #endif diff --git a/platform/android/dir_access_jandroid.h b/platform/android/dir_access_jandroid.h index 356828dcc1..5db32b945c 100644 --- a/platform/android/dir_access_jandroid.h +++ b/platform/android/dir_access_jandroid.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 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 */ @@ -58,7 +58,7 @@ class DirAccessJAndroid : public DirAccess { public: - virtual bool list_dir_begin(); ///< This starts dir listing + virtual Error list_dir_begin(); ///< This starts dir listing virtual String get_next(); virtual bool current_is_dir() const; virtual bool current_is_hidden() const; diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index bd63cadc57..204bf684b7 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -1,3 +1,31 @@ +/*************************************************************************/ +/* export.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 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 "version.h" #include "export.h" #include "tools/editor/editor_settings.h" @@ -9,6 +37,7 @@ #include "os/file_access.h" #include "os/os.h" #include "platform/android/logo.h" +#include <string.h> static const char* android_perms[]={ @@ -161,7 +190,7 @@ NULL}; class EditorExportPlatformAndroid : public EditorExportPlatform { - OBJ_TYPE( EditorExportPlatformAndroid,EditorExportPlatform ); + GDCLASS( EditorExportPlatformAndroid,EditorExportPlatform ); enum { @@ -231,6 +260,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { void _fix_manifest(Vector<uint8_t>& p_manifest, bool p_give_internet); 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); + static bool _should_compress_asset(const String& p_path, const Vector<uint8_t>& p_data); protected: @@ -465,7 +495,7 @@ static String _parse_string(const uint8_t *p_bytes,bool p_utf8) { Vector<uint8_t> str8; str8.resize(len+1); - for(int i=0;i<len;i++) { + for(uint32_t i=0;i<len;i++) { str8[i]=p_bytes[offset+i]; } str8[len]=0; @@ -475,7 +505,7 @@ static String _parse_string(const uint8_t *p_bytes,bool p_utf8) { } else { String str; - for(int i=0;i<len;i++) { + for(uint32_t i=0;i<len;i++) { CharType c = decode_uint16(&p_bytes[offset+i*2]); if (c==0) break; @@ -501,11 +531,11 @@ void EditorExportPlatformAndroid::_fix_resources(Vector<uint8_t>& p_manifest) { 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); + //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++) { + for(uint32_t 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; @@ -523,8 +553,8 @@ void EditorExportPlatformAndroid::_fix_resources(Vector<uint8_t>& p_manifest) { 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); + if (GlobalConfig::get_singleton()->has(prop)) { + str = GlobalConfig::get_singleton()->get(prop); } else { str = get_project_name(); } @@ -539,7 +569,7 @@ void EditorExportPlatformAndroid::_fix_resources(Vector<uint8_t>& p_manifest) { Vector<uint8_t> ret; ret.resize(string_table_begins+string_table.size()*4); - for(int i=0;i<string_table_begins;i++) { + for(uint32_t i=0;i<string_table_begins;i++) { ret[i]=p_manifest[i]; } @@ -587,7 +617,7 @@ void EditorExportPlatformAndroid::_fix_resources(Vector<uint8_t>& p_manifest) { p_manifest=ret; - printf("end\n"); + //printf("end\n"); } String EditorExportPlatformAndroid::get_project_name() const { @@ -596,7 +626,7 @@ String EditorExportPlatformAndroid::get_project_name() const { if (this->name!="") { aname=this->name; } else { - aname = Globals::get_singleton()->get("application/name"); + aname = GlobalConfig::get_singleton()->get("application/name"); } @@ -630,7 +660,7 @@ void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest,bool uint32_t filesize = decode_uint32(&p_manifest[ofs+4]); ofs+=8; -// print_line("FILESIZE: "+itos(filesize)+" ACTUAL: "+itos(p_manifest.size())); + //print_line("FILESIZE: "+itos(filesize)+" ACTUAL: "+itos(p_manifest.size())); uint32_t string_count; uint32_t styles_count; @@ -642,7 +672,7 @@ void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest,bool uint32_t string_table_ends; Vector<uint8_t> stable_extra; - while(ofs < p_manifest.size()) { + while(ofs < (uint32_t)p_manifest.size()) { uint32_t chunk = decode_uint32(&p_manifest[ofs]); uint32_t size = decode_uint32(&p_manifest[ofs+4]); @@ -657,7 +687,7 @@ void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest,bool string_count=decode_uint32(&p_manifest[iofs]); styles_count=decode_uint32(&p_manifest[iofs+4]); - uint32_t string_flags=decode_uint32(&p_manifest[iofs+8]); + string_flags=decode_uint32(&p_manifest[iofs+8]); string_data_offset=decode_uint32(&p_manifest[iofs+12]); styles_offset=decode_uint32(&p_manifest[iofs+16]); /* @@ -673,7 +703,7 @@ void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest,bool string_table_begins=st_offset; - for(int i=0;i<string_count;i++) { + for(uint32_t 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; @@ -689,7 +719,7 @@ void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest,bool uint32_t len = decode_uint16(&p_manifest[string_at]); Vector<CharType> ucstring; ucstring.resize(len+1); - for(int j=0;j<len;j++) { + for(uint32_t j=0;j<len;j++) { uint16_t c=decode_uint16(&p_manifest[string_at+2+2*j]); ucstring[j]=c; } @@ -699,17 +729,17 @@ void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest,bool } -// print_line("String "+itos(i)+": "+string_table[i]); + //print_line("String "+itos(i)+": "+string_table[i]); } - for(int i=string_end;i<(ofs+size);i++) { + for(uint32_t i=string_end;i<(ofs+size);i++) { stable_extra.push_back(p_manifest[i]); } -// printf("stable extra: %i\n",int(stable_extra.size())); + //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)); + //print_line("STABLE SIZE: "+itos(size)+" ACTUAL: "+itos(string_table_ends)); } break; case CHUNK_XML_START_TAG: { @@ -722,13 +752,13 @@ void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest,bool String tname=string_table[name]; -// printf("NSPACE: %i\n",nspace); + //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++) { + 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]); @@ -748,16 +778,16 @@ void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest,bool 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); + //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"); + print_line("FOUND package"); string_table[attr_value]=get_package_name(); } @@ -766,14 +796,14 @@ void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest,bool //print_line("attrname: "+attrname); if (tname=="manifest" && /*nspace=="android" &&*/ attrname=="versionCode") { - print_line("FOUND versioncode"); + print_line("FOUND versionCode"); encode_uint32(version_code,&p_manifest[iofs+16]); } if (tname=="manifest" && /*nspace=="android" &&*/ attrname=="versionName") { - print_line("FOUND versionname"); + print_line("FOUND versionName"); if (attr_value==0xFFFFFFFF) { WARN_PRINT("Version name in a resource, should be plaintext") } else @@ -792,40 +822,6 @@ void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest,bool }*/ } - 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 (but you can ignore this).") - } 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 (but you can ignore this)") - } 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; - } - } - if (tname=="uses-permission" && /*nspace=="android" &&*/ attrname=="name") { if (value.begins_with("godot.custom")) { @@ -838,10 +834,10 @@ void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest,bool } else if (value.begins_with("godot.")) { String perm = value.get_slice(".",1); - print_line("PERM: "+perm+" HAS: "+itos(perms.has(perm))); if (perms.has(perm) || (p_give_internet && perm=="INTERNET")) { + print_line("PERM: "+perm); string_table[attr_value]="android.permission."+perm; } @@ -850,13 +846,11 @@ void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest,bool if (tname=="supports-screens" ) { - if (attr_value==0xFFFFFFFF) { - WARN_PRINT("Screen res name in a resource, should be plaintext") - } else if (attrname=="smallScreens") { + if (attrname=="smallScreens") { encode_uint32(screen_support[SCREEN_SMALL]?0xFFFFFFFF:0,&p_manifest[iofs+16]); - } else if (attrname=="mediumScreens") { + } else if (attrname=="normalScreens") { encode_uint32(screen_support[SCREEN_NORMAL]?0xFFFFFFFF:0,&p_manifest[iofs+16]); @@ -877,19 +871,19 @@ void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest,bool } break; } - printf("chunk %x: size: %d\n",chunk,size); + //printf("chunk %x: size: %d\n",chunk,size); ofs+=size; } - printf("end\n"); + //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++) { + for(uint32_t i=0;i<string_table_begins;i++) { ret[i]=p_manifest[i]; } @@ -899,14 +893,14 @@ void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest,bool encode_uint32(ofs,&ret[string_table_begins+i*4]); ofs+=string_table[i].length()*2+2+2; - print_line("ofs: "+itos(i)+": "+itos(ofs)); + //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); + //print_line("savint string :"+s); encode_uint16(s.length(),chars); chars+=2; for(int j=0;j<s.length();j++) { //include zero? @@ -919,21 +913,19 @@ void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest,bool } - 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]; + ret.push_back(stable_extra[i]); } + while(ret.size()%4) + ret.push_back(0); + 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++) + for(uint32_t i=0;i<extra;i++) ret[new_stable_end+i]=p_manifest[string_table_ends+i]; while(ret.size()%4) @@ -942,7 +934,7 @@ void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest,bool encode_uint32(new_stable_end-8,&ret[12]); //update new string table size - print_line("file size: "+itos(ret.size())); + //print_line("file size: "+itos(ret.size())); p_manifest=ret; @@ -957,7 +949,7 @@ void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest,bool header[i]=decode_uint32(&p_manifest[i*4]); } - print_line("STO: "+itos(header[3])); + //print_line("STO: "+itos(header[3])); uint32_t st_offset=9*4; //ERR_FAIL_COND(header[3]!=0x24) uint32_t string_count=header[4]; @@ -1001,7 +993,7 @@ Error EditorExportPlatformAndroid::save_apk_file(void *p_userdata,const String& NULL, 0, NULL, - Z_DEFLATED, + _should_compress_asset(p_path,p_data) ? Z_DEFLATED : 0, Z_DEFAULT_COMPRESSION); @@ -1012,13 +1004,58 @@ Error EditorExportPlatformAndroid::save_apk_file(void *p_userdata,const String& } +bool EditorExportPlatformAndroid::_should_compress_asset(const String& p_path, const Vector<uint8_t>& p_data) { + + /* + * By not compressing files with little or not benefit in doing so, + * a performance gain is expected at runtime. Moreover, if the APK is + * zip-aligned, assets stored as they are can be efficiently read by + * Android by memory-mapping them. + */ + + // -- Unconditional uncompress to mimic AAPT plus some other + + static const char* unconditional_compress_ext[] = { + // From https://github.com/android/platform_frameworks_base/blob/master/tools/aapt/Package.cpp + // These formats are already compressed, or don't compress well: + ".jpg", ".jpeg", ".png", ".gif", + ".wav", ".mp2", ".mp3", ".ogg", ".aac", + ".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet", + ".rtttl", ".imy", ".xmf", ".mp4", ".m4a", + ".m4v", ".3gp", ".3gpp", ".3g2", ".3gpp2", + ".amr", ".awb", ".wma", ".wmv", + // Godot-specific: + ".webp", // Same reasoning as .png + ".cfb", // Don't let small config files slow-down startup + // Trailer for easier processing + NULL + }; + + for (const char** ext=unconditional_compress_ext; *ext; ++ext) { + if (p_path.to_lower().ends_with(String(*ext))) { + return false; + } + } + + // -- Compressed resource? + + if (p_data.size() >= 4 && p_data[0]=='R' && p_data[1]=='S' && p_data[2]=='C' && p_data[3]=='C') { + // Already compressed + return false; + } + + // --- TODO: Decide on texture resources according to their image compression setting + + return true; +} + Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_debug, int p_flags) { String src_apk; - EditorProgress ep("export","Exporting for Android",104); + EditorProgress ep("export","Exporting for Android",105); if (p_debug) src_apk=custom_debug_package; @@ -1058,7 +1095,8 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d 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); + String unaligned_path=EditorSettings::get_singleton()->get_settings_path()+"/tmp/tmpexport-unaligned.apk"; + zipFile unaligned_apk=zipOpen2(unaligned_path.utf8().get_data(),APPEND_STATUS_CREATE,NULL,&io2); while(ret==UNZ_OK) { @@ -1110,7 +1148,7 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d if (!found) { - String appicon = Globals::get_singleton()->get("application/icon"); + String appicon = GlobalConfig::get_singleton()->get("application/icon"); if (appicon!="" && appicon.ends_with(".png")) { FileAccess*f = FileAccess::open(appicon,FileAccess::READ); if (f) { @@ -1126,7 +1164,7 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d skip=true; } - if (file=="lib/armeabi/libgodot_android.so" && !export_arm) { + if (file.match("lib/armeabi*/libgodot_android.so") && !export_arm) { skip=true; } @@ -1137,7 +1175,11 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d print_line("ADDING: "+file); if (!skip) { - zipOpenNewFileInZip(apk, + + // Respect decision on compression made by AAPT for the export template + const bool uncompressed = info.compression_method == 0; + + zipOpenNewFileInZip(unaligned_apk, file.utf8().get_data(), NULL, NULL, @@ -1145,11 +1187,11 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d NULL, 0, NULL, - Z_DEFLATED, + uncompressed ? 0 : Z_DEFLATED, Z_DEFAULT_COMPRESSION); - zipWriteInFileInZip(apk,data.ptr(),data.size()); - zipCloseFileInZip(apk); + zipWriteInFileInZip(unaligned_apk,data.ptr(),data.size()); + zipCloseFileInZip(unaligned_apk); } ret = unzGoToNextFile(pkg); @@ -1170,9 +1212,9 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d if (p_flags&EXPORT_DUMB_CLIENT) { - /*String host = EditorSettings::get_singleton()->get("file_server/host"); - int port = EditorSettings::get_singleton()->get("file_server/post"); - String passwd = EditorSettings::get_singleton()->get("file_server/password"); + /*String host = EditorSettings::get_singleton()->get("filesystem/file_server/host"); + int port = EditorSettings::get_singleton()->get("filesystem/file_server/post"); + String passwd = EditorSettings::get_singleton()->get("filesystem/file_server/password"); cl.push_back("-rfs"); cl.push_back(host+":"+itos(port)); if (passwd!="") { @@ -1206,7 +1248,7 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d APKExportData ed; ed.ep=&ep; - ed.apk=apk; + ed.apk=unaligned_apk; err = export_project_files(save_apk_file,&ed,false); } @@ -1235,7 +1277,7 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d print_line(itos(i)+" param: "+cl[i]); } - zipOpenNewFileInZip(apk, + zipOpenNewFileInZip(unaligned_apk, "assets/_cl_", NULL, NULL, @@ -1243,15 +1285,15 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d NULL, 0, NULL, - Z_DEFLATED, + 0, // No compress (little size gain and potentially slower startup) Z_DEFAULT_COMPRESSION); - zipWriteInFileInZip(apk,clf.ptr(),clf.size()); - zipCloseFileInZip(apk); + zipWriteInFileInZip(unaligned_apk,clf.ptr(),clf.size()); + zipCloseFileInZip(unaligned_apk); } - zipClose(apk,NULL); + zipClose(unaligned_apk,NULL); unzClose(pkg); if (err) { @@ -1263,7 +1305,7 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d if (_signed) { - String jarsigner=EditorSettings::get_singleton()->get("android/jarsigner"); + String jarsigner=EditorSettings::get_singleton()->get("export/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; @@ -1273,9 +1315,9 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d 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"); + keystore=EditorSettings::get_singleton()->get("export/android/debug_keystore"); + password=EditorSettings::get_singleton()->get("export/android/debug_keystore_pass"); + user=EditorSettings::get_singleton()->get("export/android/debug_keystore_user"); ep.step("Signing Debug APK..",103); @@ -1298,7 +1340,7 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d args.push_back("SHA1"); args.push_back("-sigalg"); args.push_back("MD5withRSA"); - String tsa_url=EditorSettings::get_singleton()->get("android/timestamping_authority_url"); + String tsa_url=EditorSettings::get_singleton()->get("export/android/timestamping_authority_url"); if (tsa_url != "") { args.push_back("-tsa"); args.push_back(tsa_url); @@ -1308,10 +1350,10 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d args.push_back(keystore); args.push_back("-storepass"); args.push_back(password); - args.push_back(p_path); + args.push_back(unaligned_path); args.push_back(user); int retval; - int err = OS::get_singleton()->execute(jarsigner,args,true,NULL,NULL,&retval); + 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; @@ -1321,16 +1363,102 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d args.clear(); args.push_back("-verify"); - args.push_back(p_path); + args.push_back(unaligned_path); args.push_back("-verbose"); - err = OS::get_singleton()->execute(jarsigner,args,true,NULL,NULL,&retval); + 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."); + EditorNode::add_io_error("'jarsigner' verification of APK failed. Make sure to use jarsigner from Java 6."); return ERR_CANT_CREATE; } } + + + + // Let's zip-align (must be done after signing) + + static const int ZIP_ALIGNMENT = 4; + + ep.step("Aligning APK..",105); + + unzFile tmp_unaligned = unzOpen2(unaligned_path.utf8().get_data(), &io); + if (!tmp_unaligned) { + + EditorNode::add_io_error("Could not find temp unaligned APK."); + return ERR_FILE_NOT_FOUND; + } + + ERR_FAIL_COND_V(!tmp_unaligned, ERR_CANT_OPEN); + ret = unzGoToFirstFile(tmp_unaligned); + + io2=io; + dst_f=NULL; + io2.opaque=&dst_f; + zipFile final_apk=zipOpen2(p_path.utf8().get_data(),APPEND_STATUS_CREATE,NULL,&io2); + + // Take files from the unaligned APK and write them out to the aligned one + // in raw mode, i.e. not uncompressing and recompressing, aligning them as needed, + // following what is done in https://github.com/android/platform_build/blob/master/tools/zipalign/ZipAlign.cpp + int bias = 0; + while(ret==UNZ_OK) { + + unz_file_info info; + memset(&info, 0, sizeof(info)); + + char fname[16384]; + char extra[16384]; + ret = unzGetCurrentFileInfo(tmp_unaligned,&info,fname,16384,extra,16384-ZIP_ALIGNMENT,NULL,0); + + String file=fname; + + Vector<uint8_t> data; + data.resize(info.compressed_size); + + // read + int method, level; + unzOpenCurrentFile2(tmp_unaligned, &method, &level, 1); // raw read + long file_offset = unzGetCurrentFileZStreamPos64(tmp_unaligned); + unzReadCurrentFile(tmp_unaligned,data.ptr(),data.size()); + unzCloseCurrentFile(tmp_unaligned); + + // align + int padding = 0; + if (!info.compression_method) { + // Uncompressed file => Align + long new_offset = file_offset + bias; + padding = (ZIP_ALIGNMENT - (new_offset % ZIP_ALIGNMENT)) % ZIP_ALIGNMENT; + } + + memset(extra + info.size_file_extra, 0, padding); + + // write + zipOpenNewFileInZip2(final_apk, + file.utf8().get_data(), + NULL, + extra, + info.size_file_extra + padding, + NULL, + 0, + NULL, + method, + level, + 1); // raw write + zipWriteInFileInZip(final_apk,data.ptr(),data.size()); + zipCloseFileInZipRaw(final_apk,info.uncompressed_size,info.crc); + + bias += padding; + + ret = unzGoToNextFile(tmp_unaligned); + } + + zipClose(final_apk,NULL); + unzClose(tmp_unaligned); + + if (err) { + return err; + } + return OK; } @@ -1352,6 +1480,7 @@ int EditorExportPlatformAndroid::get_device_count() const { return dc; } + String EditorExportPlatformAndroid::get_device_name(int p_device) const { ERR_FAIL_INDEX_V(p_device,devices.size(),""); @@ -1360,6 +1489,7 @@ String EditorExportPlatformAndroid::get_device_name(int p_device) const { device_lock->unlock(); return s; } + String EditorExportPlatformAndroid::get_device_info(int p_device) const { ERR_FAIL_INDEX_V(p_device,devices.size(),""); @@ -1376,125 +1506,130 @@ void EditorExportPlatformAndroid::_device_poll_thread(void *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); - } + String adb=EditorSettings::get_singleton()->get("export/android/adb"); + if (FileAccess::exists(adb)) { + + String devices; + List<String> args; + args.push_back("devices"); + int ec; + 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(); + ea->device_lock->lock(); - bool different=false; + bool different=false; - if (devices.size()!=ldevices.size()) { + if (devices.size()!=ldevices.size()) { - different=true; - } else { + different=true; + } else { - for(int i=0;i<ea->devices.size();i++) { + for(int i=0;i<ea->devices.size();i++) { - if (ea->devices[i].id!=ldevices[i]) { - different=true; - break; + if (ea->devices[i].id!=ldevices[i]) { + different=true; + break; + } } } - } - if (different) { + if (different) { - Vector<Device> ndevices; + Vector<Device> ndevices; - for(int i=0;i<ldevices.size();i++) { + 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; + 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"; + 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; + + OS::get_singleton()->execute(adb,args,true,NULL,&dp,&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); + } - d.name=vendor+" "+device; -// print_line("name: "+d.name); -// print_line("description: "+d.description); + ndevices.push_back(d); } - ndevices.push_back(d); - + ea->devices=ndevices; + ea->devices_changed=true; } - ea->devices=ndevices; - ea->devices_changed=true; + ea->device_lock->unlock(); } - ea->device_lock->unlock(); + uint64_t wait = 3000000; + uint64_t time = OS::get_singleton()->get_ticks_usec(); + while(OS::get_singleton()->get_ticks_usec() - time < wait ) { + OS::get_singleton()->delay_usec(1000); + if (ea->quit_request) + break; + } - OS::get_singleton()->delay_usec(3000000); } - if (EditorSettings::get_singleton()->get("android/shutdown_adb_on_exit")) { - String adb=EditorSettings::get_singleton()->get("android/adb"); + if (EditorSettings::get_singleton()->get("export/android/shutdown_adb_on_exit")) { + String adb=EditorSettings::get_singleton()->get("export/android/adb"); if (!FileAccess::exists(adb)) { return; //adb not configured } @@ -1512,7 +1647,7 @@ Error EditorExportPlatformAndroid::run(int p_device, int p_flags) { EditorProgress ep("run","Running on "+devices[p_device].name,3); - String adb=EditorSettings::get_singleton()->get("android/adb"); + String adb=EditorSettings::get_singleton()->get("export/android/adb"); if (adb=="") { EditorNode::add_io_error("ADB executable not configured in settings, can't run."); @@ -1524,7 +1659,7 @@ Error EditorExportPlatformAndroid::run(int p_device, int p_flags) { ep.step("Exporting APK",0); - bool use_adb_over_usb = bool(EDITOR_DEF("android/use_remote_debug_over_adb",true)); + bool use_adb_over_usb = bool(EDITOR_DEF("export/android/use_remote_debug_over_adb",true)); if (use_adb_over_usb) { p_flags|=EXPORT_REMOTE_DEBUG_LOCALHOST; @@ -1584,7 +1719,7 @@ Error EditorExportPlatformAndroid::run(int p_device, int p_flags) { args.push_back("--remove-all"); err = OS::get_singleton()->execute(adb,args,true,NULL,NULL,&rv); - int port = Globals::get_singleton()->get("debug/debug_port"); + int port = GlobalConfig::get_singleton()->get("network/debug/remote_port"); args.clear(); args.push_back("reverse"); args.push_back("tcp:"+itos(port)); @@ -1593,7 +1728,7 @@ Error EditorExportPlatformAndroid::run(int p_device, int p_flags) { err = OS::get_singleton()->execute(adb,args,true,NULL,NULL,&rv); print_line("Reverse result: "+itos(rv)); - int fs_port = EditorSettings::get_singleton()->get("file_server/port"); + int fs_port = EditorSettings::get_singleton()->get("filesystem/file_server/port"); args.clear(); args.push_back("reverse"); @@ -1631,7 +1766,7 @@ Error EditorExportPlatformAndroid::run(int p_device, int p_flags) { String EditorExportPlatformAndroid::get_package_name() { String pname = package; - String basename = Globals::get_singleton()->get("application/name"); + String basename = GlobalConfig::get_singleton()->get("application/name"); basename=basename.to_lower(); String name; @@ -1687,7 +1822,7 @@ EditorExportPlatformAndroid::EditorExportPlatformAndroid() { bool EditorExportPlatformAndroid::can_export(String *r_error) const { bool valid=true; - String adb=EditorSettings::get_singleton()->get("android/adb"); + String adb=EditorSettings::get_singleton()->get("export/android/adb"); String err; if (!FileAccess::exists(adb)) { @@ -1696,7 +1831,7 @@ bool EditorExportPlatformAndroid::can_export(String *r_error) const { err+="ADB executable not configured in editor settings.\n"; } - String js = EditorSettings::get_singleton()->get("android/jarsigner"); + String js = EditorSettings::get_singleton()->get("export/android/jarsigner"); if (!FileAccess::exists(js)) { @@ -1704,7 +1839,7 @@ bool EditorExportPlatformAndroid::can_export(String *r_error) const { err+="OpenJDK 6 jarsigner not configured in editor settings.\n"; } - String dk = EditorSettings::get_singleton()->get("android/debug_keystore"); + String dk = EditorSettings::get_singleton()->get("export/android/debug_keystore"); if (!FileAccess::exists(dk)) { @@ -1729,10 +1864,12 @@ bool EditorExportPlatformAndroid::can_export(String *r_error) const { if (apk_expansion) { - //if (apk_expansion_salt=="") { - // valid=false; - // err+="Invalid SALT for apk expansion.\n"; - //} + /* + if (apk_expansion_salt=="") { + valid=false; + err+="Invalid SALT for apk expansion.\n"; + } + */ if (apk_expansion_pkey=="") { valid=false; err+="Invalid public key for apk expansion.\n"; @@ -1748,7 +1885,6 @@ bool EditorExportPlatformAndroid::can_export(String *r_error) const { EditorExportPlatformAndroid::~EditorExportPlatformAndroid() { - quit_request=true; Thread::wait_to_finish(device_thread); memdelete(device_lock); @@ -1759,24 +1895,23 @@ EditorExportPlatformAndroid::~EditorExportPlatformAndroid() { void register_android_exporter() { String exe_ext=OS::get_singleton()->get_name()=="Windows"?"exe":""; - EDITOR_DEF("android/adb",""); + EDITOR_DEF("export/android/adb",""); EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,"android/adb",PROPERTY_HINT_GLOBAL_FILE,exe_ext)); - EDITOR_DEF("android/jarsigner",""); + EDITOR_DEF("export/android/jarsigner",""); EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,"android/jarsigner",PROPERTY_HINT_GLOBAL_FILE,exe_ext)); - EDITOR_DEF("android/debug_keystore",""); + EDITOR_DEF("export/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("export/android/debug_keystore_user","androiddebugkey"); + EDITOR_DEF("export/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")); - EDITOR_DEF("android/timestamping_authority_url",""); - EDITOR_DEF("android/use_remote_debug_over_adb",false); - EDITOR_DEF("android/shutdown_adb_on_exit",true); + EDITOR_DEF("export/android/timestamping_authority_url",""); + EDITOR_DEF("export/android/use_remote_debug_over_adb",false); + EDITOR_DEF("export/android/shutdown_adb_on_exit",true); 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 index 88581802b8..468b484177 100644 --- a/platform/android/export/export.h +++ b/platform/android/export/export.h @@ -1,3 +1,29 @@ - - +/*************************************************************************/ +/* export.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 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. */ +/*************************************************************************/ void register_android_exporter(); diff --git a/platform/android/file_access_android.cpp b/platform/android/file_access_android.cpp index 334d32de0c..2828d3c074 100644 --- a/platform/android/file_access_android.cpp +++ b/platform/android/file_access_android.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 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 */ @@ -74,6 +74,7 @@ void FileAccessAndroid::close() { AAsset_close(a); a=NULL; } + bool FileAccessAndroid::is_open() const { return a!=NULL; @@ -92,6 +93,7 @@ void FileAccessAndroid::seek(size_t p_position) { } } + void FileAccessAndroid::seek_end(int64_t p_position) { ERR_FAIL_COND(!a); @@ -99,10 +101,12 @@ void FileAccessAndroid::seek_end(int64_t p_position) { pos=len+p_position; } + size_t FileAccessAndroid::get_pos() const { return pos; } + size_t FileAccessAndroid::get_len() const { return len; @@ -128,6 +132,7 @@ uint8_t FileAccessAndroid::get_8() const { return byte; } + int FileAccessAndroid::get_buffer(uint8_t *p_dst, int p_length) const { diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h index 3fcd7836c3..3d54eb2027 100644 --- a/platform/android/file_access_android.h +++ b/platform/android/file_access_android.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 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 */ diff --git a/platform/android/file_access_jandroid.cpp b/platform/android/file_access_jandroid.cpp index da8ceaff14..a4e9c191e9 100644 --- a/platform/android/file_access_jandroid.cpp +++ b/platform/android/file_access_jandroid.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 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 */ @@ -90,6 +90,7 @@ void FileAccessJAndroid::close() { id=0; } + bool FileAccessJAndroid::is_open() const { return id!=0; @@ -102,6 +103,7 @@ 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()); @@ -109,6 +111,7 @@ void FileAccessJAndroid::seek_end(int64_t p_position) { seek(get_len()); } + size_t FileAccessJAndroid::get_pos() const { JNIEnv *env = ThreadAndroid::get_env(); @@ -116,13 +119,13 @@ size_t FileAccessJAndroid::get_pos() const { 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 { @@ -167,7 +170,6 @@ Error FileAccessJAndroid::get_error() const { void FileAccessJAndroid::store_8(uint8_t p_dest) { - } bool FileAccessJAndroid::file_exists(const String& p_path) { @@ -182,8 +184,10 @@ bool FileAccessJAndroid::file_exists(const String& p_path) { jstring js = env->NewStringUTF(path.utf8().get_data()); int res = env->CallIntMethod(io,_file_open,js,false); - if (res<=0) + if (res<=0) { + env->DeleteLocalRef(js); return false; + } env->CallVoidMethod(io,_file_close,res); env->DeleteLocalRef(js); return true; @@ -193,7 +197,6 @@ bool FileAccessJAndroid::file_exists(const String& p_path) { void FileAccessJAndroid::setup( jobject p_io) { - io=p_io; JNIEnv *env = ThreadAndroid::get_env(); @@ -233,18 +236,16 @@ void FileAccessJAndroid::setup( jobject p_io) { __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_close ok!!"); } -// (*env)->CallVoidMethod(env,obj,aMethodID, myvar); + //(*env)->CallVoidMethod(env,obj,aMethodID, myvar); } -FileAccessJAndroid::FileAccessJAndroid() -{ +FileAccessJAndroid::FileAccessJAndroid() { id=0; } -FileAccessJAndroid::~FileAccessJAndroid() -{ +FileAccessJAndroid::~FileAccessJAndroid() { if (is_open()) close(); diff --git a/platform/android/file_access_jandroid.h b/platform/android/file_access_jandroid.h index d576af93d6..38f441ea71 100644 --- a/platform/android/file_access_jandroid.h +++ b/platform/android/file_access_jandroid.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 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 */ diff --git a/platform/android/globals/global_defaults.cpp b/platform/android/globals/global_defaults.cpp index 824a4e3606..bbf9bd5b0b 100644 --- a/platform/android/globals/global_defaults.cpp +++ b/platform/android/globals/global_defaults.cpp @@ -1,14 +1,42 @@ - +/*************************************************************************/ +/* global_defaults.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 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 "global_defaults.h" #include "globals.h" void register_android_global_defaults() { - GLOBAL_DEF("rasterizer.Android/use_fragment_lighting",false); +/* GLOBAL_DEF("rasterizer.Android/use_fragment_lighting",false); GLOBAL_DEF("rasterizer.Android/fp16_framebuffer",false); GLOBAL_DEF("display.Android/driver","GLES2"); -// GLOBAL_DEF("rasterizer.Android/trilinear_mipmap_filter",false); + //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,"GLES2")); + GlobalConfig::get_singleton()->set_custom_property_info("display.Android/driver",PropertyInfo(Variant::STRING,"display.Android/driver",PROPERTY_HINT_ENUM,"GLES2")); + */ } diff --git a/platform/android/globals/global_defaults.h b/platform/android/globals/global_defaults.h index 11617ddfd0..49d7f6393c 100644 --- a/platform/android/globals/global_defaults.h +++ b/platform/android/globals/global_defaults.h @@ -1,3 +1,29 @@ - - +/*************************************************************************/ +/* global_defaults.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 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. */ +/*************************************************************************/ void register_android_global_defaults(); diff --git a/platform/android/godot_android.cpp b/platform/android/godot_android.cpp index edb051575f..3c7f7f5854 100644 --- a/platform/android/godot_android.cpp +++ b/platform/android/godot_android.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 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 */ @@ -57,7 +57,7 @@ extern "C" { class JNISingleton : public Object { - OBJ_TYPE( JNISingleton, Object ); + GDCLASS( JNISingleton, Object ); struct MethodData { @@ -153,7 +153,7 @@ public: } break; case Variant::STRING_ARRAY: { - DVector<String> sarray = *p_args[i]; + PoolVector<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++) { @@ -165,18 +165,18 @@ public: } break; case Variant::INT_ARRAY: { - DVector<int> array = *p_args[i]; + PoolVector<int> array = *p_args[i]; jintArray arr = env->NewIntArray(array.size()); - DVector<int>::Read r = array.read(); + PoolVector<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]; + PoolVector<float> array = *p_args[i]; jfloatArray arr = env->NewFloatArray(array.size()); - DVector<float>::Read r = array.read(); + PoolVector<float>::Read r = array.read(); env->SetFloatArrayRegion(arr,0,array.size(),r.ptr()); v[i].l=arr; @@ -225,7 +225,7 @@ public: jobjectArray arr = (jobjectArray)env->CallObjectMethodA(instance,E->get().method,v); int stringCount = env->GetArrayLength(arr); - DVector<String> sarr; + PoolVector<String> sarr; for (int i=0; i<stringCount; i++) { jstring string = (jstring) env->GetObjectArrayElement(arr, i); @@ -241,12 +241,12 @@ public: jintArray arr = (jintArray)env->CallObjectMethodA(instance,E->get().method,v); int fCount = env->GetArrayLength(arr); - DVector<int> sarr; + PoolVector<int> sarr; sarr.resize(fCount); - DVector<int>::Write w = sarr.write(); + PoolVector<int>::Write w = sarr.write(); env->GetIntArrayRegion(arr,0,fCount,w.ptr()); - w = DVector<int>::Write(); + w = PoolVector<int>::Write(); ret=sarr; } break; case Variant::REAL_ARRAY: { @@ -254,12 +254,12 @@ public: jfloatArray arr = (jfloatArray)env->CallObjectMethodA(instance,E->get().method,v); int fCount = env->GetArrayLength(arr); - DVector<float> sarr; + PoolVector<float> sarr; sarr.resize(fCount); - DVector<float>::Write w = sarr.write(); + PoolVector<float>::Write w = sarr.write(); env->GetFloatArrayRegion(arr,0,fCount,w.ptr()); - w = DVector<float>::Write(); + w = PoolVector<float>::Write(); ret=sarr; } break; default: { @@ -314,6 +314,7 @@ struct engine { ASensorManager* sensorManager; const ASensor* accelerometerSensor; const ASensor* magnetometerSensor; + const ASensor* gyroscopeSensor; ASensorEventQueue* sensorEventQueue; bool display_active; @@ -534,29 +535,33 @@ static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) 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()); + //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)); - //} + /* + 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)); + //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)); + //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)); - //} + /* + for(int i=0;i<event.getPointerCount();i++) { + System.out.printf("%d - up! %f,%f\n",i, event.getX(i),event.getY(i)); + } + */ } break; } @@ -637,8 +642,8 @@ static void engine_handle_cmd(struct android_app* app, int32_t cmd) { } break; case APP_CMD_INIT_WINDOW: - //The window is being shown, get it ready. - // LOGI("INIT WINDOW"); + //The window is being shown, get it ready. + //LOGI("INIT WINDOW"); if (engine->app->window != NULL) { if (engine->os==NULL) { @@ -646,14 +651,14 @@ static void engine_handle_cmd(struct android_app* app, int32_t cmd) { //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}; + //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"); + String modules = GlobalConfig::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()); @@ -721,15 +726,15 @@ static void engine_handle_cmd(struct android_app* app, int32_t cmd) { engine->animating=1; engine_draw_frame(engine); } - break; + break; case APP_CMD_TERM_WINDOW: - // The window is being hidden or closed, clean it up. - // LOGI("TERM WINDOW"); - engine_term_display(engine); - break; + // 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) { + // 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). @@ -746,6 +751,15 @@ static void engine_handle_cmd(struct android_app* app, int32_t cmd) { engine->magnetometerSensor, (1000L/60)*1000); } + // And the gyroscope. + if (engine->gyroscopeSensor != NULL) { + ASensorEventQueue_enableSensor(engine->sensorEventQueue, + engine->gyroscopeSensor); + // We'd like to get 60 events per second (in us). + ASensorEventQueue_setEventRate(engine->sensorEventQueue, + engine->gyroscopeSensor, (1000L/60)*1000); + + } engine->animating = 1; break; case APP_CMD_LOST_FOCUS: @@ -759,6 +773,10 @@ static void engine_handle_cmd(struct android_app* app, int32_t cmd) { ASensorEventQueue_disableSensor(engine->sensorEventQueue, engine->magnetometerSensor); } + if (engine->gyroscopeSensor != NULL) { + ASensorEventQueue_disableSensor(engine->sensorEventQueue, + engine->gyroscopeSensor); + } // Also stop animating. engine->animating = 0; engine_draw_frame(engine); @@ -788,6 +806,8 @@ void android_main(struct android_app* state) { ASENSOR_TYPE_ACCELEROMETER); engine.magnetometerSensor = ASensorManager_getDefaultSensor(engine.sensorManager, ASENSOR_TYPE_MAGNETIC_FIELD); + engine.gyroscopeSensor = ASensorManager_getDefaultSensor(engine.sensorManager, + ASENSOR_TYPE_GYROSCOPE); engine.sensorEventQueue = ASensorManager_createEventQueue(engine.sensorManager, state->looper, LOOPER_ID_USER, NULL, NULL); @@ -817,7 +837,7 @@ void android_main(struct android_app* state) { // Process this event. if (source != NULL) { - // LOGI("process\n"); + // LOGI("process\n"); source->process(state, source); } else { nullmax--; @@ -828,7 +848,7 @@ void android_main(struct android_app* state) { // If a sensor has data, process it now. // LOGI("events\n"); if (ident == LOOPER_ID_USER) { - if (engine.accelerometerSensor != NULL || engine.magnetometerSensor != NULL) { + if (engine.accelerometerSensor != NULL || engine.magnetometerSensor != NULL || engine.gyroscopeSensor != NULL) { ASensorEvent event; while (ASensorEventQueue_getEvents(engine.sensorEventQueue, &event, 1) > 0) { @@ -843,6 +863,10 @@ void android_main(struct android_app* state) { engine.os->process_magnetometer(Vector3(event.magnetic.x, event.magnetic.y, event.magnetic.z)); } + if (event.vector != NULL) { + engine.os->process_gyroscope(Vector3(event.vector.x, event.vector.y, + event.vector.z)); + } } } @@ -863,12 +887,12 @@ void android_main(struct android_app* state) { return; } -// LOGI("end\n"); + // LOGI("end\n"); } -// LOGI("engine animating? %i\n",engine.animating); + // LOGI("engine animating? %i\n",engine.animating); if (engine.animating) { //do os render @@ -892,7 +916,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_Godot_registerSingleton(JNIEnv s->set_instance(env->NewGlobalRef(p_object)); jni_singletons[singname]=s; - Globals::get_singleton()->add_singleton(Globals::Singleton(singname,s)); + GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton(singname,s)); } @@ -910,7 +934,7 @@ static Variant::Type get_jni_type(const String& p_type) { {"java.lang.String",Variant::STRING}, {"[I",Variant::INT_ARRAY}, {"[F",Variant::REAL_ARRAY}, - {"[java.lang.String",Variant::STRING_ARRAY}, + {"[Ljava.lang.String;",Variant::STRING_ARRAY}, {NULL,Variant::NIL} }; @@ -941,7 +965,7 @@ static const char* get_jni_sig(const String& p_type) { {"java.lang.String","Ljava/lang/String;"}, {"[I","[I"}, {"[F","[F"}, - {"[java.lang.String","[Ljava/lang/String;"}, + {"[Ljava.lang.String;","[Ljava/lang/String;"}, {NULL,"V"} }; @@ -963,7 +987,7 @@ JNIEXPORT jstring JNICALL Java_org_godotengine_godot_Godot_getGlobal(JNIEnv * en String js = env->GetStringUTFChars( path, NULL ); - return env->NewStringUTF(Globals::get_singleton()->get(js).operator String().utf8().get_data()); + return env->NewStringUTF(GlobalConfig::get_singleton()->get(js).operator String().utf8().get_data()); } diff --git a/platform/android/ifaddrs_android.cpp b/platform/android/ifaddrs_android.cpp index c1e9eb3584..f6d5cdbe77 100644 --- a/platform/android/ifaddrs_android.cpp +++ b/platform/android/ifaddrs_android.cpp @@ -38,13 +38,16 @@ #include <errno.h> #include <linux/netlink.h> #include <linux/rtnetlink.h> + struct netlinkrequest { nlmsghdr header; ifaddrmsg msg; }; + namespace { const int kMaxReadSize = 4096; -}; +} + static int set_ifname(struct ifaddrs* ifaddr, int interface) { char buf[IFNAMSIZ] = {0}; char* name = if_indextoname(interface, buf); @@ -55,6 +58,7 @@ static int set_ifname(struct ifaddrs* ifaddr, int interface) { strncpy(ifaddr->ifa_name, name, strlen(name) + 1); return 0; } + static int set_flags(struct ifaddrs* ifaddr) { int fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd == -1) { @@ -71,6 +75,7 @@ static int set_flags(struct ifaddrs* ifaddr) { ifaddr->ifa_flags = ifr.ifr_flags; return 0; } + static int set_addresses(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* data, size_t len) { if (msg->ifa_family == AF_INET) { @@ -89,6 +94,7 @@ static int set_addresses(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* data, } return 0; } + static int make_prefixes(struct ifaddrs* ifaddr, int family, int prefixlen) { char* prefix = NULL; if (family == AF_INET) { @@ -120,6 +126,7 @@ static int make_prefixes(struct ifaddrs* ifaddr, int family, int prefixlen) { *prefix = remainder; return 0; } + static int populate_ifaddrs(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* bytes, size_t len) { if (set_ifname(ifaddr, msg->ifa_index) != 0) { @@ -136,6 +143,7 @@ static int populate_ifaddrs(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* bytes, } return 0; } + int getifaddrs(struct ifaddrs** result) { int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (fd < 0) { @@ -207,6 +215,7 @@ int getifaddrs(struct ifaddrs** result) { freeifaddrs(start); return -1; } + void freeifaddrs(struct ifaddrs* addrs) { struct ifaddrs* last = NULL; struct ifaddrs* cursor = addrs; diff --git a/platform/android/java/gradle/wrapper/gradle-wrapper.properties b/platform/android/java/gradle/wrapper/gradle-wrapper.properties index 0c71e760dc..d57051703e 100644 --- a/platform/android/java/gradle/wrapper/gradle-wrapper.properties +++ b/platform/android/java/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip diff --git a/platform/android/java/res/drawable-hdpi/notify_panel_notification_icon_bg.png b/platform/android/java/res/drawable-hdpi/notify_panel_notification_icon_bg.png Binary files differindex f5b762ecf3..94bc406416 100644 --- a/platform/android/java/res/drawable-hdpi/notify_panel_notification_icon_bg.png +++ b/platform/android/java/res/drawable-hdpi/notify_panel_notification_icon_bg.png diff --git a/platform/android/java/res/drawable-mdpi/notify_panel_notification_icon_bg.png b/platform/android/java/res/drawable-mdpi/notify_panel_notification_icon_bg.png Binary files differindex 9ecb8af06c..ef6fe4e836 100644 --- a/platform/android/java/res/drawable-mdpi/notify_panel_notification_icon_bg.png +++ b/platform/android/java/res/drawable-mdpi/notify_panel_notification_icon_bg.png diff --git a/platform/android/java/res/drawable/icon.png b/platform/android/java/res/drawable/icon.png Binary files differindex e334f5fa78..a0a0f4af25 100644 --- a/platform/android/java/res/drawable/icon.png +++ b/platform/android/java/res/drawable/icon.png diff --git a/platform/android/java/res/layout/downloading_expansion.xml b/platform/android/java/res/layout/downloading_expansion.xml index 553155dcd3..d678d94eac 100644 --- a/platform/android/java/res/layout/downloading_expansion.xml +++ b/platform/android/java/res/layout/downloading_expansion.xml @@ -80,7 +80,7 @@ </RelativeLayout> <LinearLayout - android:id="@+id/downloaderDashboard" + android:id="@+id/downloadButton" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" > diff --git a/platform/android/java/res/values-fa/strings.xml b/platform/android/java/res/values-fa/strings.xml index 450f9fe212..f1e29013c4 100644 --- a/platform/android/java/res/values-fa/strings.xml +++ b/platform/android/java/res/values-fa/strings.xml @@ -1,7 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <resources> <string name="godot_project_name_string">godot-project-name-fa</string> - <string name="testuf8">سلام</string> <string name="text_paused_cellular">آیا می خواهید بر روی اتصال داده همراه دانلود را شروع کنید؟ بر اساس نوع سطح داده شما این ممکن است برای شما هزینه مالی داشته باشد.</string> <string name="text_paused_cellular_2">اگر نمی خواهید بر روی اتصال داده همراه دانلود را شروع کنید ، دانلود به صورت خودکار در زمان دسترسی به وای-فای شروع می شود.</string> <string name="text_button_resume_cellular">ادامه دانلود</string> diff --git a/platform/android/java/res/values-id/strings.xml b/platform/android/java/res/values-in/strings.xml index 9e9a8b0c03..9e9a8b0c03 100644 --- a/platform/android/java/res/values-id/strings.xml +++ b/platform/android/java/res/values-in/strings.xml diff --git a/platform/android/java/res/values-he/strings.xml b/platform/android/java/res/values-iw/strings.xml index f52ede2085..f52ede2085 100644 --- a/platform/android/java/res/values-he/strings.xml +++ b/platform/android/java/res/values-iw/strings.xml diff --git a/platform/android/java/res/values-zh/strings.xml b/platform/android/java/res/values-zh-rCN/strings.xml index 397e662851..6668c56bd9 100644 --- a/platform/android/java/res/values-zh/strings.xml +++ b/platform/android/java/res/values-zh-rCN/strings.xml @@ -1,4 +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 +</resources> diff --git a/platform/android/java/res/values-zh-rHK/strings.xml b/platform/android/java/res/values-zh-rHK/strings.xml new file mode 100644 index 0000000000..8a6269da0f --- /dev/null +++ b/platform/android/java/res/values-zh-rHK/strings.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="godot_project_name_string">godot-project-name-zh_HK</string> +</resources> diff --git a/platform/android/java/res/values-zh-rTW/strings.xml b/platform/android/java/res/values-zh-rTW/strings.xml new file mode 100644 index 0000000000..b1bb39d5d6 --- /dev/null +++ b/platform/android/java/res/values-zh-rTW/strings.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="godot_project_name_string">godot-project-name-zh_TW</string> +</resources> diff --git a/platform/android/java/src/com/android/vending/billing/IInAppBillingService.aidl b/platform/android/java/src/com/android/vending/billing/IInAppBillingService.aidl deleted file mode 100644 index 2a492f7845..0000000000 --- a/platform/android/java/src/com/android/vending/billing/IInAppBillingService.aidl +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2012 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. - */ - -package com.android.vending.billing; - -import android.os.Bundle; - -/** - * InAppBillingService is the service that provides in-app billing version 3 and beyond. - * This service provides the following features: - * 1. Provides a new API to get details of in-app items published for the app including - * price, type, title and description. - * 2. The purchase flow is synchronous and purchase information is available immediately - * after it completes. - * 3. Purchase information of in-app purchases is maintained within the Google Play system - * till the purchase is consumed. - * 4. An API to consume a purchase of an inapp item. All purchases of one-time - * in-app items are consumable and thereafter can be purchased again. - * 5. An API to get current purchases of the user immediately. This will not contain any - * consumed purchases. - * - * All calls will give a response code with the following possible values - * RESULT_OK = 0 - success - * RESULT_USER_CANCELED = 1 - user pressed back or canceled a dialog - * RESULT_BILLING_UNAVAILABLE = 3 - this billing API version is not supported for the type requested - * RESULT_ITEM_UNAVAILABLE = 4 - requested SKU is not available for purchase - * RESULT_DEVELOPER_ERROR = 5 - invalid arguments provided to the API - * RESULT_ERROR = 6 - Fatal error during the API action - * RESULT_ITEM_ALREADY_OWNED = 7 - Failure to purchase since item is already owned - * RESULT_ITEM_NOT_OWNED = 8 - Failure to consume since item is not owned - */ -interface IInAppBillingService { - /** - * Checks support for the requested billing API version, package and in-app type. - * Minimum API version supported by this interface is 3. - * @param apiVersion the billing version which the app is using - * @param packageName the package name of the calling app - * @param type type of the in-app item being purchased "inapp" for one-time purchases - * and "subs" for subscription. - * @return RESULT_OK(0) on success, corresponding result code on failures - */ - int isBillingSupported(int apiVersion, String packageName, String type); - - /** - * Provides details of a list of SKUs - * Given a list of SKUs of a valid type in the skusBundle, this returns a bundle - * with a list JSON strings containing the productId, price, title and description. - * This API can be called with a maximum of 20 SKUs. - * @param apiVersion billing API version that the Third-party is using - * @param packageName the package name of the calling app - * @param skusBundle bundle containing a StringArrayList of SKUs with key "ITEM_ID_LIST" - * @return Bundle containing the following key-value pairs - * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on - * failure as listed above. - * "DETAILS_LIST" with a StringArrayList containing purchase information - * in JSON format similar to: - * '{ "productId" : "exampleSku", "type" : "inapp", "price" : "$5.00", - * "title : "Example Title", "description" : "This is an example description" }' - */ - Bundle getSkuDetails(int apiVersion, String packageName, String type, in Bundle skusBundle); - - /** - * Returns a pending intent to launch the purchase flow for an in-app item by providing a SKU, - * the type, a unique purchase token and an optional developer payload. - * @param apiVersion billing API version that the app is using - * @param packageName package name of the calling app - * @param sku the SKU of the in-app item as published in the developer console - * @param type the type of the in-app item ("inapp" for one-time purchases - * and "subs" for subscription). - * @param developerPayload optional argument to be sent back with the purchase information - * @return Bundle containing the following key-value pairs - * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on - * failure as listed above. - * "BUY_INTENT" - PendingIntent to start the purchase flow - * - * The Pending intent should be launched with startIntentSenderForResult. When purchase flow - * has completed, the onActivityResult() will give a resultCode of OK or CANCELED. - * If the purchase is successful, the result data will contain the following key-value pairs - * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on - * failure as listed above. - * "INAPP_PURCHASE_DATA" - String in JSON format similar to - * '{"orderId":"12999763169054705758.1371079406387615", - * "packageName":"com.example.app", - * "productId":"exampleSku", - * "purchaseTime":1345678900000, - * "purchaseToken" : "122333444455555", - * "developerPayload":"example developer payload" }' - * "INAPP_DATA_SIGNATURE" - String containing the signature of the purchase data that - * was signed with the private key of the developer - * TODO: change this to app-specific keys. - */ - Bundle getBuyIntent(int apiVersion, String packageName, String sku, String type, - String developerPayload); - - /** - * Returns the current SKUs owned by the user of the type and package name specified along with - * purchase information and a signature of the data to be validated. - * This will return all SKUs that have been purchased in V3 and managed items purchased using - * V1 and V2 that have not been consumed. - * @param apiVersion billing API version that the app is using - * @param packageName package name of the calling app - * @param type the type of the in-app items being requested - * ("inapp" for one-time purchases and "subs" for subscription). - * @param continuationToken to be set as null for the first call, if the number of owned - * skus are too many, a continuationToken is returned in the response bundle. - * This method can be called again with the continuation token to get the next set of - * owned skus. - * @return Bundle containing the following key-value pairs - * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on - * failure as listed above. - * "INAPP_PURCHASE_ITEM_LIST" - StringArrayList containing the list of SKUs - * "INAPP_PURCHASE_DATA_LIST" - StringArrayList containing the purchase information - * "INAPP_DATA_SIGNATURE_LIST"- StringArrayList containing the signatures - * of the purchase information - * "INAPP_CONTINUATION_TOKEN" - String containing a continuation token for the - * next set of in-app purchases. Only set if the - * user has more owned skus than the current list. - */ - Bundle getPurchases(int apiVersion, String packageName, String type, String continuationToken); - - /** - * Consume the last purchase of the given SKU. This will result in this item being removed - * from all subsequent responses to getPurchases() and allow re-purchase of this item. - * @param apiVersion billing API version that the app is using - * @param packageName package name of the calling app - * @param purchaseToken token in the purchase information JSON that identifies the purchase - * to be consumed - * @return 0 if consumption succeeded. Appropriate error values for failures. - */ - int consumePurchase(int apiVersion, String packageName, String purchaseToken); -} diff --git a/platform/android/java/src/com/android/vending/licensing/LicenseChecker.java b/platform/android/java/src/com/android/vending/licensing/LicenseChecker.java index 0b1c4b6cca..531cb22f8c 100644 --- a/platform/android/java/src/com/android/vending/licensing/LicenseChecker.java +++ b/platform/android/java/src/com/android/vending/licensing/LicenseChecker.java @@ -146,11 +146,11 @@ public class LicenseChecker implements ServiceConnection { if (mService == null) { Log.i(TAG, "Binding to licensing service."); try { + Intent serviceIntent = new Intent(new String(Base64.decode("Y29tLmFuZHJvaWQudmVuZGluZy5saWNlbnNpbmcuSUxpY2Vuc2luZ1NlcnZpY2U="))); + serviceIntent.setPackage("com.android.vending"); boolean bindResult = mContext .bindService( - new Intent( - new String( - Base64.decode("Y29tLmFuZHJvaWQudmVuZGluZy5saWNlbnNpbmcuSUxpY2Vuc2luZ1NlcnZpY2U="))), + serviceIntent, this, // ServiceConnection. Context.BIND_AUTO_CREATE); diff --git a/platform/android/java/src/com/google/android/vending/expansion/downloader/Constants.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/Constants.java index ff2c6f535a..2af33b96b9 100644 --- a/platform/android/java/src/com/google/android/vending/expansion/downloader/Constants.java +++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/Constants.java @@ -33,6 +33,10 @@ public class Constants { public static final String EXP_PATH = File.separator + "Android" + File.separator + "obb" + File.separator; + // save to private app's data on Android 6.0 to skip requesting permission. + public static final String EXP_PATH_API23 = File.separator + "Android" + + File.separator + "data" + File.separator; + /** The intent that gets sent when the service must wake up for a retry */ public static final String ACTION_RETRY = "android.intent.action.DOWNLOAD_WAKEUP"; @@ -70,7 +74,7 @@ public class Constants { * The number of times that the download manager will retry its network * operations when no progress is happening before it gives up. */ - public static final int MAX_RETRIES = 5; + public static final int MAX_RETRIES = 10; /** * The minimum amount of time that the download manager accepts for diff --git a/platform/android/java/src/com/google/android/vending/expansion/downloader/Helpers.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/Helpers.java index b4c28d36e7..ae3fe957cb 100644 --- a/platform/android/java/src/com/google/android/vending/expansion/downloader/Helpers.java +++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/Helpers.java @@ -19,6 +19,7 @@ package com.google.android.vending.expansion.downloader; import com.godot.game.R; import android.content.Context; +import android.os.Build; import android.os.Environment; import android.os.StatFs; import android.os.SystemClock; @@ -220,8 +221,8 @@ public class Helpers { static public String getSaveFilePath(Context c) { File root = Environment.getExternalStorageDirectory(); - String path = root.toString() + Constants.EXP_PATH + c.getPackageName(); - return path; + String path = Build.VERSION.SDK_INT >= 23 ? Constants.EXP_PATH_API23 : Constants.EXP_PATH; + return root.toString() + path + c.getPackageName(); } /** diff --git a/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/CustomNotificationFactory.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/CustomNotificationFactory.java index 9a0ca02122..e2673a9dd7 100644 --- a/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/CustomNotificationFactory.java +++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/CustomNotificationFactory.java @@ -25,6 +25,6 @@ public class CustomNotificationFactory { if (android.os.Build.VERSION.SDK_INT > 13) return new V14CustomNotification(); else - return new V3CustomNotification(); + throw new RuntimeException(); } } diff --git a/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java index d82b658bc3..73e6f83bec 100644 --- a/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java +++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java @@ -27,6 +27,7 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.os.Messenger; +import android.support.v4.app.NotificationCompat; /** * This class handles displaying the notification associated with the download @@ -48,8 +49,9 @@ public class DownloadNotification implements IDownloaderClient { private IDownloaderClient mClientProxy; final ICustomNotification mCustomNotification; - private Notification mNotification; - private Notification mCurrentNotification; + // NotificationCompat.Builder is used to support API < 16. This can be changed to Notification.Builder if minimum API >= 16. + private NotificationCompat.Builder mNotificationBuilder; + private NotificationCompat.Builder mCurrentNotificationBuilder; private CharSequence mLabel; private String mCurrentText; private PendingIntent mContentIntent; @@ -132,17 +134,14 @@ public class DownloadNotification implements IDownloaderClient { } mCurrentText = mContext.getString(stringDownloadID); mCurrentTitle = mLabel.toString(); - mCurrentNotification.tickerText = mLabel + ": " + mCurrentText; - mCurrentNotification.icon = iconResource; - mCurrentNotification.setLatestEventInfo(mContext, mCurrentTitle, mCurrentText, - mContentIntent); - if (ongoingEvent) { - mCurrentNotification.flags |= Notification.FLAG_ONGOING_EVENT; - } else { - mCurrentNotification.flags &= ~Notification.FLAG_ONGOING_EVENT; - mCurrentNotification.flags |= Notification.FLAG_AUTO_CANCEL; - } - mNotificationManager.notify(NOTIFICATION_ID, mCurrentNotification); + mCurrentNotificationBuilder.setTicker(mLabel + ": " + mCurrentText); + mCurrentNotificationBuilder.setSmallIcon(iconResource); + mCurrentNotificationBuilder.setContentTitle(mCurrentTitle); + mCurrentNotificationBuilder.setContentText(mCurrentText); + mCurrentNotificationBuilder.setContentIntent(mContentIntent); + mCurrentNotificationBuilder.setOngoing(ongoingEvent); + mCurrentNotificationBuilder.setAutoCancel(!ongoingEvent); + mNotificationManager.notify(NOTIFICATION_ID, mCurrentNotificationBuilder.build()); } } @@ -154,10 +153,12 @@ public class DownloadNotification implements IDownloaderClient { } if (progress.mOverallTotal <= 0) { // we just show the text - mNotification.tickerText = mCurrentTitle; - mNotification.icon = android.R.drawable.stat_sys_download; - mNotification.setLatestEventInfo(mContext, mLabel, mCurrentText, mContentIntent); - mCurrentNotification = mNotification; + mNotificationBuilder.setTicker(mCurrentTitle); + mNotificationBuilder.setSmallIcon(android.R.drawable.stat_sys_download); + mNotificationBuilder.setContentTitle(mCurrentTitle); + mNotificationBuilder.setContentText(mCurrentText); + mNotificationBuilder.setContentIntent(mContentIntent); + mCurrentNotificationBuilder = mNotificationBuilder; } else { mCustomNotification.setCurrentBytes(progress.mOverallProgress); mCustomNotification.setTotalBytes(progress.mOverallTotal); @@ -166,9 +167,9 @@ public class DownloadNotification implements IDownloaderClient { mCustomNotification.setTicker(mLabel + ": " + mCurrentText); mCustomNotification.setTitle(mLabel); mCustomNotification.setTimeRemaining(progress.mTimeRemaining); - mCurrentNotification = mCustomNotification.updateNotification(mContext); + mCurrentNotificationBuilder = mCustomNotification.updateNotification(mContext); } - mNotificationManager.notify(NOTIFICATION_ID, mCurrentNotification); + mNotificationManager.notify(NOTIFICATION_ID, mCurrentNotificationBuilder.build()); } public interface ICustomNotification { @@ -186,7 +187,7 @@ public class DownloadNotification implements IDownloaderClient { void setTimeRemaining(long timeRemaining); - Notification updateNotification(Context c); + NotificationCompat.Builder updateNotification(Context c); } /** @@ -219,8 +220,8 @@ public class DownloadNotification implements IDownloaderClient { mContext.getSystemService(Context.NOTIFICATION_SERVICE); mCustomNotification = CustomNotificationFactory .createCustomNotification(); - mNotification = new Notification(); - mCurrentNotification = mNotification; + mNotificationBuilder = new NotificationCompat.Builder(ctx); + mCurrentNotificationBuilder = mNotificationBuilder; } diff --git a/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/V14CustomNotification.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/V14CustomNotification.java index 2e049a4d47..390bde96e9 100644 --- a/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/V14CustomNotification.java +++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/V14CustomNotification.java @@ -22,6 +22,7 @@ import com.google.android.vending.expansion.downloader.Helpers; import android.app.Notification; import android.app.PendingIntent; import android.content.Context; +import android.support.v4.app.NotificationCompat; public class V14CustomNotification implements DownloadNotification.ICustomNotification { @@ -53,13 +54,14 @@ public class V14CustomNotification implements DownloadNotification.ICustomNotifi mCurrentKB = currentBytes; } - void setProgress(Notification.Builder builder) { + void setProgress(NotificationCompat.Builder builder) { } @Override - public Notification updateNotification(Context c) { - Notification.Builder builder = new Notification.Builder(c); + public NotificationCompat.Builder updateNotification(Context c) { + // NotificationCompat.Builder is used to support API < 16. This can be changed to Notification.Builder if minimum API >= 16. + NotificationCompat.Builder builder = new NotificationCompat.Builder(c); builder.setContentTitle(mTitle); if (mTotalKB > 0 && -1 != mCurrentKB) { builder.setProgress((int) (mTotalKB >> 8), (int) (mCurrentKB >> 8), false); @@ -80,7 +82,7 @@ public class V14CustomNotification implements DownloadNotification.ICustomNotifi builder.setContentIntent(mPendingIntent); builder.setOnlyAlertOnce(true); - return builder.getNotification(); + return builder; } @Override diff --git a/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/V3CustomNotification.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/V3CustomNotification.java deleted file mode 100644 index 94e21de7ca..0000000000 --- a/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/V3CustomNotification.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2012 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. - */ - -package com.google.android.vending.expansion.downloader.impl; - -import com.godot.game.R; -import com.google.android.vending.expansion.downloader.Helpers; - -import android.app.Notification; -import android.app.PendingIntent; -import android.content.Context; -import android.graphics.BitmapFactory; -import android.view.View; -import android.widget.RemoteViews; - -public class V3CustomNotification implements DownloadNotification.ICustomNotification { - - CharSequence mTitle; - CharSequence mTicker; - int mIcon; - long mTotalBytes = -1; - long mCurrentBytes = -1; - long mTimeRemaining; - PendingIntent mPendingIntent; - Notification mNotification = new Notification(); - - @Override - public void setIcon(int icon) { - mIcon = icon; - } - - @Override - public void setTitle(CharSequence title) { - mTitle = title; - } - - @Override - public void setTotalBytes(long totalBytes) { - mTotalBytes = totalBytes; - } - - @Override - public void setCurrentBytes(long currentBytes) { - mCurrentBytes = currentBytes; - } - - @Override - public Notification updateNotification(Context c) { - Notification n = mNotification; - - n.icon = mIcon; - - n.flags |= Notification.FLAG_ONGOING_EVENT; - - if (android.os.Build.VERSION.SDK_INT > 10) { - n.flags |= Notification.FLAG_ONLY_ALERT_ONCE; // only matters for - // Honeycomb - } - - // Build the RemoteView object - RemoteViews expandedView = new RemoteViews( - c.getPackageName(), - R.layout.status_bar_ongoing_event_progress_bar); - - expandedView.setTextViewText(R.id.title, mTitle); - // look at strings - expandedView.setViewVisibility(R.id.description, View.VISIBLE); - expandedView.setTextViewText(R.id.description, - Helpers.getDownloadProgressString(mCurrentBytes, mTotalBytes)); - expandedView.setViewVisibility(R.id.progress_bar_frame, View.VISIBLE); - expandedView.setProgressBar(R.id.progress_bar, - (int) (mTotalBytes >> 8), - (int) (mCurrentBytes >> 8), - mTotalBytes <= 0); - expandedView.setViewVisibility(R.id.time_remaining, View.VISIBLE); - expandedView.setTextViewText( - R.id.time_remaining, - c.getString(R.string.time_remaining_notification, - Helpers.getTimeRemaining(mTimeRemaining))); - expandedView.setTextViewText(R.id.progress_text, - Helpers.getDownloadProgressPercent(mCurrentBytes, mTotalBytes)); - expandedView.setImageViewResource(R.id.appIcon, mIcon); - n.contentView = expandedView; - n.contentIntent = mPendingIntent; - return n; - } - - @Override - public void setPendingIntent(PendingIntent contentIntent) { - mPendingIntent = contentIntent; - } - - @Override - public void setTicker(CharSequence ticker) { - mTicker = ticker; - } - - @Override - public void setTimeRemaining(long timeRemaining) { - mTimeRemaining = timeRemaining; - } - -} diff --git a/platform/android/java/src/org/godotengine/godot/Dictionary.java b/platform/android/java/src/org/godotengine/godot/Dictionary.java index 34051c4bb8..72f0b7a60e 100644 --- a/platform/android/java/src/org/godotengine/godot/Dictionary.java +++ b/platform/android/java/src/org/godotengine/godot/Dictionary.java @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 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 */ diff --git a/platform/android/java/src/org/godotengine/godot/Godot.java b/platform/android/java/src/org/godotengine/godot/Godot.java index c4ba2da751..610f707b47 100644 --- a/platform/android/java/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/src/org/godotengine/godot/Godot.java @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 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 */ @@ -115,7 +115,17 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC private int mState; private boolean keep_screen_on=true; - private void setState(int newState) { + static private Intent mCurrentIntent; + + @Override public void onNewIntent(Intent intent) { + mCurrentIntent = intent; + } + + static public Intent getCurrentIntent() { + return mCurrentIntent; + } + + private void setState(int newState) { if (mState != newState) { mState = newState; mStatusText.setText(Helpers.getDownloaderStringResourceIDFromState(newState)); @@ -207,6 +217,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC private SensorManager mSensorManager; private Sensor mAccelerometer; private Sensor mMagnetometer; + private Sensor mGyroscope; public FrameLayout layout; public RelativeLayout adLayout; @@ -246,8 +257,8 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC public void onVideoInit(boolean use_gl2) { -// mView = new GodotView(getApplication(),io,use_gl2); -// setContentView(mView); + //mView = new GodotView(getApplication(),io,use_gl2); + //setContentView(mView); layout = new FrameLayout(this); layout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT)); @@ -284,6 +295,25 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC }); } } + + public void alert(final String message, final String title) { + runOnUiThread(new Runnable() { + @Override + public void run() { + AlertDialog.Builder builder = new AlertDialog.Builder(getInstance()); + builder.setMessage(message).setTitle(title); + builder.setPositiveButton( + "OK", + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + } + }); + AlertDialog dialog = builder.create(); + dialog.show(); + } + }); + } private static Godot _self; @@ -377,6 +407,8 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME); mMagnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_GAME); + mGyroscope = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); + mSensorManager.registerListener(this, mGyroscope, SensorManager.SENSOR_DELAY_GAME); result_callback = null; @@ -467,7 +499,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC // Build the full path to the app's expansion files try { - expansion_pack_path = Environment.getExternalStorageDirectory().toString() + "/Android/obb/"+this.getPackageName(); + expansion_pack_path = Helpers.getSaveFilePath(getApplicationContext()); expansion_pack_path+="/"+"main."+getPackageManager().getPackageInfo(getPackageName(), 0).versionCode+"."+this.getPackageName()+".obb"; } catch (Exception e) { e.printStackTrace(); @@ -545,10 +577,12 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC } } + mCurrentIntent = getIntent(); + initializeGodot(); - // instanceSingleton( new GodotFacebook(this) ); + //instanceSingleton( new GodotFacebook(this) ); } @@ -590,8 +624,9 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC } mView.onResume(); - mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL); - mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_NORMAL); + 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(); @@ -658,6 +693,9 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC if (typeOfSensor == event.sensor.TYPE_MAGNETIC_FIELD) { GodotLib.magnetometer(x,y,z); } + if (typeOfSensor == event.sensor.TYPE_GYROSCOPE) { + GodotLib.gyroscope(x,y,z); + } } @Override public final void onAccuracyChanged(Sensor sensor, int accuracy) { @@ -683,7 +721,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC @Override public void onBackPressed() { System.out.printf("** BACK REQUEST!\n"); - GodotLib.quit(); + GodotLib.back(); } public void forceQuit() { @@ -766,9 +804,11 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC } 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)); - //} + /* + 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(); @@ -784,9 +824,11 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC 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)); - //} + /* + for(int i=0;i<event.getPointerCount();i++) { + System.out.printf("%d - up! %f,%f\n",i, event.getX(i),event.getY(i)); + } + */ } break; } @@ -828,9 +870,11 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC return mPaymentsManager; } -// public void setPaymentsManager(PaymentsManager mPaymentsManager) { -// this.mPaymentsManager = mPaymentsManager; -// }; + /* + public void setPaymentsManager(PaymentsManager mPaymentsManager) { + this.mPaymentsManager = mPaymentsManager; + } + */ // Audio diff --git a/platform/android/java/src/org/godotengine/godot/GodotDownloaderAlarmReceiver.java b/platform/android/java/src/org/godotengine/godot/GodotDownloaderAlarmReceiver.java index b602f4757c..5a07d680b3 100644 --- a/platform/android/java/src/org/godotengine/godot/GodotDownloaderAlarmReceiver.java +++ b/platform/android/java/src/org/godotengine/godot/GodotDownloaderAlarmReceiver.java @@ -1,3 +1,31 @@ +/*************************************************************************/ +/* GodotDownloaderAlarmReceiver.java */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 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 org.godotengine.godot; import com.google.android.vending.expansion.downloader.DownloaderClientMarshaller; diff --git a/platform/android/java/src/org/godotengine/godot/GodotDownloaderService.java b/platform/android/java/src/org/godotengine/godot/GodotDownloaderService.java index 6735d387f3..fba082e80d 100644 --- a/platform/android/java/src/org/godotengine/godot/GodotDownloaderService.java +++ b/platform/android/java/src/org/godotengine/godot/GodotDownloaderService.java @@ -1,3 +1,31 @@ +/*************************************************************************/ +/* GodotDownloaderService.java */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 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 org.godotengine.godot; import android.content.Context; @@ -29,7 +57,7 @@ public class GodotDownloaderService extends DownloaderService { Log.d("GODOT", "getting public key:" + prefs.getString("store_public_key", null)); return prefs.getString("store_public_key", null); -// return BASE64_PUBLIC_KEY; + //return BASE64_PUBLIC_KEY; } /** diff --git a/platform/android/java/src/org/godotengine/godot/GodotIO.java b/platform/android/java/src/org/godotengine/godot/GodotIO.java index 3e6919c2ad..33c1c03ace 100644 --- a/platform/android/java/src/org/godotengine/godot/GodotIO.java +++ b/platform/android/java/src/org/godotengine/godot/GodotIO.java @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 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 */ @@ -40,6 +40,7 @@ import android.view.*; import android.view.inputmethod.InputMethodManager; import android.os.*; import android.util.Log; +import android.util.DisplayMetrics; import android.graphics.*; import android.text.method.*; import android.text.*; @@ -287,6 +288,11 @@ public class GodotIO { try { ad.files = am.list(path); + // no way to find path is directory or file exactly. + // but if ad.files.length==0, then it's an empty directory or file. + if (ad.files.length==0) { + return -1; + } } catch (IOException e) { System.out.printf("Exception on dir_open: %s\n",e); @@ -513,6 +519,11 @@ public class GodotIO { return Build.MODEL; } + public int getScreenDPI() { + DisplayMetrics metrics = applicationContext.getResources().getDisplayMetrics(); + return (int)(metrics.density * 160f); + } + public boolean needsReloadHooks() { return android.os.Build.VERSION.SDK_INT < 11; diff --git a/platform/android/java/src/org/godotengine/godot/GodotLib.java b/platform/android/java/src/org/godotengine/godot/GodotLib.java index df181ae1bb..57856cfd6b 100644 --- a/platform/android/java/src/org/godotengine/godot/GodotLib.java +++ b/platform/android/java/src/org/godotengine/godot/GodotLib.java @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 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 */ @@ -52,6 +52,7 @@ public class GodotLib { 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 magnetometer(float x, float y, float z); + public static native void gyroscope(float x, float y, float z); public static native void key(int p_scancode, int p_unicode_char, boolean p_pressed); public static native void joybutton(int p_device, int p_but, boolean p_pressed); public static native void joyaxis(int p_device, int p_axis, float p_value); diff --git a/platform/android/java/src/org/godotengine/godot/GodotPaymentV3.java b/platform/android/java/src/org/godotengine/godot/GodotPaymentV3.java index 6bec49410d..6eee8da91b 100644 --- a/platform/android/java/src/org/godotengine/godot/GodotPaymentV3.java +++ b/platform/android/java/src/org/godotengine/godot/GodotPaymentV3.java @@ -1,98 +1,121 @@ +/*************************************************************************/ +/* GodotPaymentV3.java */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 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 org.godotengine.godot; -import org.godotengine.godot.Dictionary; import android.app.Activity; import android.util.Log; +import org.godotengine.godot.payments.PaymentsManager; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + public class GodotPaymentV3 extends Godot.SingletonBase { private Godot activity; - private Integer purchaseCallbackId = 0; - private String accessToken; - private String purchaseValidationUrlPrefix; - private String transactionId; + private PaymentsManager mPaymentManager; + private Dictionary mSkuDetails = new Dictionary(); - public void purchase( String _sku, String _transactionId) { - final String sku = _sku; - final String transactionId = _transactionId; - activity.getPaymentsManager().setBaseSingleton(this); + public void purchase(final String sku, final String transactionId) { activity.runOnUiThread(new Runnable() { @Override public void run() { - activity.getPaymentsManager().requestPurchase(sku, transactionId); + mPaymentManager.requestPurchase(sku, transactionId); } }); } - -/* public string requestPurchasedTicket(){ - activity.getPaymentsManager() - } -*/ - static public Godot.SingletonBase initialize(Activity p_activity) { + static public Godot.SingletonBase initialize(Activity p_activity) { - return new GodotPaymentV3(p_activity); - } + return new GodotPaymentV3(p_activity); + } - public GodotPaymentV3(Activity p_activity) { - registerClass("GodotPayments", new String[] {"purchase", "setPurchaseCallbackId", "setPurchaseValidationUrlPrefix", "setTransactionId", "getSignature", "consumeUnconsumedPurchases", "requestPurchased", "setAutoConsume", "consume"}); - activity=(Godot) p_activity; + registerClass("GodotPayments", new String[]{"purchase", "setPurchaseCallbackId", "setPurchaseValidationUrlPrefix", "setTransactionId", "getSignature", "consumeUnconsumedPurchases", "requestPurchased", "setAutoConsume", "consume", "querySkuDetails"}); + activity = (Godot) p_activity; + mPaymentManager = activity.getPaymentsManager(); + mPaymentManager.setBaseSingleton(this); } - public void consumeUnconsumedPurchases(){ - activity.getPaymentsManager().setBaseSingleton(this); + public void consumeUnconsumedPurchases() { activity.runOnUiThread(new Runnable() { @Override public void run() { - activity.getPaymentsManager().consumeUnconsumedPurchases(); + mPaymentManager.consumeUnconsumedPurchases(); } }); } private String signature; - public String getSignature(){ - return this.signature; + + public String getSignature() { + return this.signature; } - - - public void callbackSuccess(String ticket, String signature, String sku){ -// Log.d(this.getClass().getName(), "PRE-Send callback to purchase success"); + + public void callbackSuccess(String ticket, String signature, String sku) { GodotLib.callobject(purchaseCallbackId, "purchase_success", new Object[]{ticket, signature, sku}); -// Log.d(this.getClass().getName(), "POST-Send callback to purchase success"); -} + } + + public void callbackSuccessProductMassConsumed(String ticket, String signature, String sku) { + Log.d(this.getClass().getName(), "callbackSuccessProductMassConsumed > " + ticket + "," + signature + "," + sku); + GodotLib.calldeferred(purchaseCallbackId, "consume_success", new Object[]{ticket, signature, sku}); + } - public void callbackSuccessProductMassConsumed(String ticket, String signature, String sku){ -// Log.d(this.getClass().getName(), "PRE-Send callback to consume success"); - Log.d(this.getClass().getName(), "callbackSuccessProductMassConsumed > "+ticket+","+signature+","+sku); - GodotLib.calldeferred(purchaseCallbackId, "consume_success", new Object[]{ticket, signature, sku}); -// Log.d(this.getClass().getName(), "POST-Send callback to consume success"); + public void callbackSuccessNoUnconsumedPurchases() { + GodotLib.calldeferred(purchaseCallbackId, "consume_not_required", new Object[]{}); } - public void callbackSuccessNoUnconsumedPurchases(){ - GodotLib.calldeferred(purchaseCallbackId, "no_validation_required", new Object[]{}); + public void callbackFailConsume() { + GodotLib.calldeferred(purchaseCallbackId, "consume_fail", new Object[]{}); } - - public void callbackFail(){ + + public void callbackFail() { GodotLib.calldeferred(purchaseCallbackId, "purchase_fail", new Object[]{}); -// GodotLib.callobject(purchaseCallbackId, "purchase_fail", new Object[]{}); } - - public void callbackCancel(){ + + public void callbackCancel() { GodotLib.calldeferred(purchaseCallbackId, "purchase_cancel", new Object[]{}); -// GodotLib.callobject(purchaseCallbackId, "purchase_cancel", new Object[]{}); } - - public void callbackAlreadyOwned(String sku){ + + public void callbackAlreadyOwned(String sku) { GodotLib.calldeferred(purchaseCallbackId, "purchase_owned", new Object[]{sku}); } - + public int getPurchaseCallbackId() { return purchaseCallbackId; } @@ -101,11 +124,11 @@ public class GodotPaymentV3 extends Godot.SingletonBase { this.purchaseCallbackId = purchaseCallbackId; } - public String getPurchaseValidationUrlPrefix(){ - return this.purchaseValidationUrlPrefix ; + public String getPurchaseValidationUrlPrefix() { + return this.purchaseValidationUrlPrefix; } - public void setPurchaseValidationUrlPrefix(String url){ + public void setPurchaseValidationUrlPrefix(String url) { this.purchaseValidationUrlPrefix = url; } @@ -116,39 +139,80 @@ public class GodotPaymentV3 extends Godot.SingletonBase { public void setAccessToken(String accessToken) { this.accessToken = accessToken; } - - public void setTransactionId(String transactionId){ + + public void setTransactionId(String transactionId) { this.transactionId = transactionId; } - - public String getTransactionId(){ + + public String getTransactionId() { return this.transactionId; } - + // request purchased items are not consumed - public void requestPurchased(){ - activity.getPaymentsManager().setBaseSingleton(this); + public void requestPurchased() { activity.runOnUiThread(new Runnable() { @Override public void run() { - activity.getPaymentsManager().requestPurchased(); + mPaymentManager.requestPurchased(); } }); } - + // callback for requestPurchased() - public void callbackPurchased(String receipt, String signature, String sku){ + public void callbackPurchased(String receipt, String signature, String sku) { GodotLib.calldeferred(purchaseCallbackId, "has_purchased", new Object[]{receipt, signature, sku}); } - + // consume item automatically after purchase. default is true. - public void setAutoConsume(boolean autoConsume){ - activity.getPaymentsManager().setAutoConsume(autoConsume); + public void setAutoConsume(boolean autoConsume) { + mPaymentManager.setAutoConsume(autoConsume); } - + // consume a specific item - public void consume(String sku){ - activity.getPaymentsManager().consume(sku); + public void consume(String sku) { + mPaymentManager.consume(sku); + } + + // query in app item detail info + public void querySkuDetails(String[] list) { + List<String> nKeys = Arrays.asList(list); + List<String> cKeys = Arrays.asList(mSkuDetails.get_keys()); + ArrayList<String> fKeys = new ArrayList<String>(); + for (String key : nKeys) { + if (!cKeys.contains(key)) { + fKeys.add(key); + } + } + if (fKeys.size() > 0) { + mPaymentManager.querySkuDetails(fKeys.toArray(new String[0])); + } else { + completeSkuDetail(); + } + } + + public void addSkuDetail(String itemJson) { + JSONObject o = null; + try { + o = new JSONObject(itemJson); + Dictionary item = new Dictionary(); + item.put("type", o.optString("type")); + item.put("product_id", o.optString("productId")); + item.put("title", o.optString("title")); + item.put("description", o.optString("description")); + item.put("price", o.optString("price")); + item.put("price_currency_code", o.optString("price_currency_code")); + item.put("price_amount", 0.000001d * o.optLong("price_amount_micros")); + mSkuDetails.put(item.get("product_id").toString(), item); + } catch (JSONException e) { + e.printStackTrace(); + } + } + + public void completeSkuDetail() { + GodotLib.calldeferred(purchaseCallbackId, "sku_details_complete", new Object[]{mSkuDetails}); + } + + public void errorSkuDetail(String errorMessage) { + GodotLib.calldeferred(purchaseCallbackId, "sku_details_error", new Object[]{errorMessage}); } } - diff --git a/platform/android/java/src/org/godotengine/godot/GodotView.java b/platform/android/java/src/org/godotengine/godot/GodotView.java index e210161e8b..4cfe295835 100644 --- a/platform/android/java/src/org/godotengine/godot/GodotView.java +++ b/platform/android/java/src/org/godotengine/godot/GodotView.java @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 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 */ @@ -265,7 +265,7 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { if (keyCode == KeyEvent.KEYCODE_BACK) { GodotLib.quit(); // press 'back' button should not terminate program - // normal handle 'back' event in game logic + //normal handle 'back' event in game logic return true; } diff --git a/platform/android/java/src/org/godotengine/godot/input/GodotEditText.java b/platform/android/java/src/org/godotengine/godot/input/GodotEditText.java index c8ffa74ecd..f0dae03a81 100644 --- a/platform/android/java/src/org/godotengine/godot/input/GodotEditText.java +++ b/platform/android/java/src/org/godotengine/godot/input/GodotEditText.java @@ -1,3 +1,31 @@ +/*************************************************************************/ +/* GodotEditText.java */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 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 org.godotengine.godot.input; import android.content.Context; import android.util.AttributeSet; 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 64d8826b44..80cded6fb5 100644 --- a/platform/android/java/src/org/godotengine/godot/input/GodotTextInputWrapper.java +++ b/platform/android/java/src/org/godotengine/godot/input/GodotTextInputWrapper.java @@ -1,3 +1,31 @@ +/*************************************************************************/ +/* GodotTextInputWrapper.java */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 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 org.godotengine.godot.input; import android.content.Context; import android.text.Editable; diff --git a/platform/android/java/src/org/godotengine/godot/payments/ConsumeTask.java b/platform/android/java/src/org/godotengine/godot/payments/ConsumeTask.java index 61ccb97161..67293df2a8 100644 --- a/platform/android/java/src/org/godotengine/godot/payments/ConsumeTask.java +++ b/platform/android/java/src/org/godotengine/godot/payments/ConsumeTask.java @@ -1,3 +1,31 @@ +/*************************************************************************/ +/* ConsumeTask.java */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 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 org.godotengine.godot.payments; import com.android.vending.billing.IInAppBillingService; @@ -19,19 +47,19 @@ abstract public class ConsumeTask { public void consume(final String sku){ -// Log.d("XXX", "Consuming product " + sku); + //Log.d("XXX", "Consuming product " + sku); PaymentsCache pc = new PaymentsCache(context); Boolean isBlocked = pc.getConsumableFlag("block", sku); String _token = pc.getConsumableValue("token", sku); -// Log.d("XXX", "token " + _token); + //Log.d("XXX", "token " + _token); if(!isBlocked && _token == null){ -// _token = "inapp:"+context.getPackageName()+":android.test.purchased"; -// Log.d("XXX", "Consuming product " + sku + " with token " + _token); + //_token = "inapp:"+context.getPackageName()+":android.test.purchased"; + //Log.d("XXX", "Consuming product " + sku + " with token " + _token); }else if(!isBlocked){ -// Log.d("XXX", "It is not blocked ¿?"); + //Log.d("XXX", "It is not blocked ¿?"); return; }else if(_token == null){ -// Log.d("XXX", "No token available"); + //Log.d("XXX", "No token available"); this.error("No token for sku:" + sku); return; } @@ -41,9 +69,9 @@ abstract public class ConsumeTask { @Override protected String doInBackground(String... params) { try { -// Log.d("XXX", "Requesting to release item."); + //Log.d("XXX", "Requesting to release item."); int response = mService.consumePurchase(3, context.getPackageName(), token); -// Log.d("XXX", "release response code: " + response); + //Log.d("XXX", "release response code: " + response); if(response == 0 || response == 8){ return null; } diff --git a/platform/android/java/src/org/godotengine/godot/payments/GenericConsumeTask.java b/platform/android/java/src/org/godotengine/godot/payments/GenericConsumeTask.java index 293e903284..dfa363ed75 100644 --- a/platform/android/java/src/org/godotengine/godot/payments/GenericConsumeTask.java +++ b/platform/android/java/src/org/godotengine/godot/payments/GenericConsumeTask.java @@ -1,3 +1,31 @@ +/*************************************************************************/ +/* GenericConsumeTask.java */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 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 org.godotengine.godot.payments; import com.android.vending.billing.IInAppBillingService; @@ -32,9 +60,9 @@ abstract public class GenericConsumeTask extends AsyncTask<String, String, Strin @Override protected String doInBackground(String... params) { try { -// Log.d("godot", "Requesting to consume an item with token ." + token); + //Log.d("godot", "Requesting to consume an item with token ." + token); int response = mService.consumePurchase(3, context.getPackageName(), token); -// Log.d("godot", "consumePurchase response: " + response); + //Log.d("godot", "consumePurchase response: " + response); if(response == 0 || response == 8){ return null; } diff --git a/platform/android/java/src/org/godotengine/godot/payments/HandlePurchaseTask.java b/platform/android/java/src/org/godotengine/godot/payments/HandlePurchaseTask.java index d120551e4a..3850453a77 100644 --- a/platform/android/java/src/org/godotengine/godot/payments/HandlePurchaseTask.java +++ b/platform/android/java/src/org/godotengine/godot/payments/HandlePurchaseTask.java @@ -1,3 +1,31 @@ +/*************************************************************************/ +/* HandlePurchaseTask.java */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 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 org.godotengine.godot.payments; import org.json.JSONException; @@ -28,29 +56,29 @@ abstract public class HandlePurchaseTask { public void handlePurchaseRequest(int resultCode, Intent data){ -// Log.d("XXX", "Handling purchase response"); -// int responseCode = data.getIntExtra("RESPONSE_CODE", 0); + //Log.d("XXX", "Handling purchase response"); + //int responseCode = data.getIntExtra("RESPONSE_CODE", 0); PaymentsCache pc = new PaymentsCache(context); String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA"); -// Log.d("XXX", "Purchase data:" + purchaseData); + //Log.d("XXX", "Purchase data:" + purchaseData); String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE"); //Log.d("XXX", "Purchase signature:" + dataSignature); if (resultCode == Activity.RESULT_OK) { try { -// Log.d("SARLANGA", purchaseData); + //Log.d("SARLANGA", purchaseData); JSONObject jo = new JSONObject(purchaseData); -// String sku = jo.getString("productId"); -// alert("You have bought the " + sku + ". Excellent choice, aventurer!"); -// String orderId = jo.getString("orderId"); -// String packageName = jo.getString("packageName"); + //String sku = jo.getString("productId"); + //alert("You have bought the " + sku + ". Excellent choice, aventurer!"); + //String orderId = jo.getString("orderId"); + //String packageName = jo.getString("packageName"); String productId = jo.getString("productId"); -// Long purchaseTime = jo.getLong("purchaseTime"); -// Integer state = jo.getInt("purchaseState"); + //Long purchaseTime = jo.getLong("purchaseTime"); + //Integer state = jo.getInt("purchaseState"); String developerPayload = jo.getString("developerPayload"); String purchaseToken = jo.getString("purchaseToken"); @@ -58,7 +86,7 @@ abstract public class HandlePurchaseTask { error("Untrusted callback"); return; } -// Log.d("XXX", "Este es el product ID:" + productId); + //Log.d("XXX", "Este es el product ID:" + productId); pc.setConsumableValue("ticket_signautre", productId, dataSignature); pc.setConsumableValue("ticket", productId, purchaseData); pc.setConsumableFlag("block", productId, true); diff --git a/platform/android/java/src/org/godotengine/godot/payments/PaymentsCache.java b/platform/android/java/src/org/godotengine/godot/payments/PaymentsCache.java index 5f3d931593..4678dae1b3 100644 --- a/platform/android/java/src/org/godotengine/godot/payments/PaymentsCache.java +++ b/platform/android/java/src/org/godotengine/godot/payments/PaymentsCache.java @@ -1,3 +1,31 @@ +/*************************************************************************/ +/* PaymentsCache.java */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 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 org.godotengine.godot.payments; import android.content.Context; @@ -31,14 +59,14 @@ public class PaymentsCache { SharedPreferences sharedPref = context.getSharedPreferences("consumables_" + set, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPref.edit(); editor.putString(sku, value); -// Log.d("XXX", "Setting asset: consumables_" + set + ":" + sku); + //Log.d("XXX", "Setting asset: consumables_" + set + ":" + sku); editor.commit(); } public String getConsumableValue(String set, String sku){ SharedPreferences sharedPref = context.getSharedPreferences( "consumables_" + set, Context.MODE_PRIVATE); -// Log.d("XXX", "Getting asset: consumables_" + set + ":" + sku); + //Log.d("XXX", "Getting asset: consumables_" + set + ":" + sku); return sharedPref.getString(sku, null); } diff --git a/platform/android/java/src/org/godotengine/godot/payments/PaymentsManager.java b/platform/android/java/src/org/godotengine/godot/payments/PaymentsManager.java index effb58aa35..73d1cc3bc8 100644 --- a/platform/android/java/src/org/godotengine/godot/payments/PaymentsManager.java +++ b/platform/android/java/src/org/godotengine/godot/payments/PaymentsManager.java @@ -1,282 +1,397 @@ +/*************************************************************************/ +/* PaymentsManager.java */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 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 org.godotengine.godot.payments; -import java.util.ArrayList; -import java.util.List; - -import android.os.RemoteException; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.os.Bundle; import android.os.IBinder; +import android.os.RemoteException; +import android.text.TextUtils; import android.util.Log; -import android.os.Bundle; -import org.json.JSONException; -import org.json.JSONObject; -import org.json.JSONStringer; +import com.android.vending.billing.IInAppBillingService; -import org.godotengine.godot.Dictionary; import org.godotengine.godot.Godot; import org.godotengine.godot.GodotPaymentV3; -import com.android.vending.billing.IInAppBillingService; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.Arrays; public class PaymentsManager { public static final int BILLING_RESPONSE_RESULT_OK = 0; public static final int REQUEST_CODE_FOR_PURCHASE = 0x1001; private static boolean auto_consume = true; - + private Activity activity; IInAppBillingService mService; - public void setActivity(Activity activity){ + public void setActivity(Activity activity) { this.activity = activity; } - public static PaymentsManager createManager(Activity activity){ + public static PaymentsManager createManager(Activity activity) { PaymentsManager manager = new PaymentsManager(activity); return manager; } - - private PaymentsManager(Activity activity){ + + private PaymentsManager(Activity activity) { this.activity = activity; } - - public PaymentsManager initService(){ + + public PaymentsManager initService() { Intent intent = new Intent("com.android.vending.billing.InAppBillingService.BIND"); intent.setPackage("com.android.vending"); activity.bindService( - intent, - mServiceConn, + intent, + mServiceConn, Context.BIND_AUTO_CREATE); return this; } - public void destroy(){ + public void destroy() { if (mService != null) { - activity.unbindService(mServiceConn); - } + activity.unbindService(mServiceConn); + } } - + ServiceConnection mServiceConn = new ServiceConnection() { - @Override - public void onServiceDisconnected(ComponentName name) { - mService = null; - } + @Override + public void onServiceDisconnected(ComponentName name) { + mService = null; + } - @Override - public void onServiceConnected(ComponentName name, IBinder service) { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { mService = IInAppBillingService.Stub.asInterface(service); - } + } }; - - public void requestPurchase(final String sku, String transactionId){ + + public void requestPurchase(final String sku, String transactionId) { new PurchaseTask(mService, Godot.getInstance()) { - + @Override protected void error(String message) { godotPaymentV3.callbackFail(); - + } - + @Override protected void canceled() { godotPaymentV3.callbackCancel(); } - + @Override protected void alreadyOwned() { godotPaymentV3.callbackAlreadyOwned(sku); } - + }.purchase(sku, transactionId); } - public void consumeUnconsumedPurchases(){ + public void consumeUnconsumedPurchases() { new ReleaseAllConsumablesTask(mService, activity) { - + @Override protected void success(String sku, String receipt, String signature, String token) { godotPaymentV3.callbackSuccessProductMassConsumed(receipt, signature, sku); } - + @Override protected void error(String message) { - godotPaymentV3.callbackFail(); - + Log.d("godot", "consumeUnconsumedPurchases :" + message); + godotPaymentV3.callbackFailConsume(); + } @Override protected void notRequired() { + Log.d("godot", "callbackSuccessNoUnconsumedPurchases :"); godotPaymentV3.callbackSuccessNoUnconsumedPurchases(); - + } }.consumeItAll(); } - - public void requestPurchased(){ - try{ + + public void requestPurchased() { + try { PaymentsCache pc = new PaymentsCache(Godot.getInstance()); -// Log.d("godot", "requestPurchased for " + activity.getPackageName()); - Bundle bundle = mService.getPurchases(3, activity.getPackageName(), "inapp",null); + String continueToken = null; -/* - for (String key : bundle.keySet()) { - Object value = bundle.get(key); - Log.d("godot", String.format("%s %s (%s)", key, value.toString(), value.getClass().getName())); - } -*/ - - if (bundle.getInt("RESPONSE_CODE") == 0){ + do { + Bundle bundle = mService.getPurchases(3, activity.getPackageName(), "inapp", continueToken); - final ArrayList<String> myPurchases = bundle.getStringArrayList("INAPP_PURCHASE_DATA_LIST"); - final ArrayList<String> mySignatures = bundle.getStringArrayList("INAPP_DATA_SIGNATURE_LIST"); - + if (bundle.getInt("RESPONSE_CODE") == 0) { - if (myPurchases == null || myPurchases.size() == 0){ -// Log.d("godot", "No purchases!"); - godotPaymentV3.callbackPurchased("", "", ""); - return; - } - -// Log.d("godot", "# products are purchased:" + myPurchases.size()); - for (int i=0;i<myPurchases.size();i++) - { - - try{ - String receipt = myPurchases.get(i); - JSONObject inappPurchaseData = new JSONObject(receipt); - String sku = inappPurchaseData.getString("productId"); - String token = inappPurchaseData.getString("purchaseToken"); - String signature = mySignatures.get(i); -// Log.d("godot", "purchased item:" + token + "\n" + receipt); - - pc.setConsumableValue("ticket_signautre", sku, signature); - pc.setConsumableValue("ticket", sku, receipt); - pc.setConsumableFlag("block", sku, true); - pc.setConsumableValue("token", sku, token); - - godotPaymentV3.callbackPurchased(receipt, signature, sku); - } catch (JSONException e) { + final ArrayList<String> myPurchases = bundle.getStringArrayList("INAPP_PURCHASE_DATA_LIST"); + final ArrayList<String> mySignatures = bundle.getStringArrayList("INAPP_DATA_SIGNATURE_LIST"); + + if (myPurchases == null || myPurchases.size() == 0) { + godotPaymentV3.callbackPurchased("", "", ""); + return; } - } - } - }catch(Exception e){ + for (int i = 0; i < myPurchases.size(); i++) { + + try { + String receipt = myPurchases.get(i); + JSONObject inappPurchaseData = new JSONObject(receipt); + String sku = inappPurchaseData.getString("productId"); + String token = inappPurchaseData.getString("purchaseToken"); + String signature = mySignatures.get(i); + + pc.setConsumableValue("ticket_signautre", sku, signature); + pc.setConsumableValue("ticket", sku, receipt); + pc.setConsumableFlag("block", sku, true); + pc.setConsumableValue("token", sku, token); + + godotPaymentV3.callbackPurchased(receipt, signature, sku); + } catch (JSONException e) { + } + } + } + continueToken = bundle.getString("INAPP_CONTINUATION_TOKEN"); + Log.d("godot", "continue token = " + continueToken); + } while (!TextUtils.isEmpty(continueToken)); + } catch (Exception e) { Log.d("godot", "Error requesting purchased products:" + e.getClass().getName() + ":" + e.getMessage()); } } - + public void processPurchaseResponse(int resultCode, Intent data) { - new HandlePurchaseTask(activity){ + new HandlePurchaseTask(activity) { @Override protected void success(final String sku, final String signature, final String ticket) { godotPaymentV3.callbackSuccess(ticket, signature, sku); - if (auto_consume){ + if (auto_consume) { new ConsumeTask(mService, activity) { - + @Override protected void success(String ticket) { -// godotPaymentV3.callbackSuccess(""); } - + @Override protected void error(String message) { godotPaymentV3.callbackFail(); - + } }.consume(sku); } - -// godotPaymentV3.callbackSuccess(new PaymentsCache(activity).getConsumableValue("ticket", sku),signature); -// godotPaymentV3.callbackSuccess(ticket); - //validatePurchase(purchaseToken, sku); } @Override protected void error(String message) { godotPaymentV3.callbackFail(); - } @Override protected void canceled() { godotPaymentV3.callbackCancel(); - } }.handlePurchaseRequest(resultCode, data); } - - public void validatePurchase(String purchaseToken, final String sku){ - - new ValidateTask(activity, godotPaymentV3){ + + public void validatePurchase(String purchaseToken, final String sku) { + + new ValidateTask(activity, godotPaymentV3) { @Override protected void success() { - + new ConsumeTask(mService, activity) { - + @Override protected void success(String ticket) { godotPaymentV3.callbackSuccess(ticket, null, sku); - } - + @Override protected void error(String message) { godotPaymentV3.callbackFail(); - } }.consume(sku); - + } @Override protected void error(String message) { godotPaymentV3.callbackFail(); - } @Override protected void canceled() { godotPaymentV3.callbackCancel(); - } }.validatePurchase(sku); } - - public void setAutoConsume(boolean autoConsume){ + + public void setAutoConsume(boolean autoConsume) { auto_consume = autoConsume; } - - public void consume(final String sku){ + + public void consume(final String sku) { new ConsumeTask(mService, activity) { - + @Override protected void success(String ticket) { godotPaymentV3.callbackSuccessProductMassConsumed(ticket, "", sku); - } - + @Override protected void error(String message) { - godotPaymentV3.callbackFail(); - + godotPaymentV3.callbackFailConsume(); } }.consume(sku); } - + + // Workaround to bug where sometimes response codes come as Long instead of Integer + int getResponseCodeFromBundle(Bundle b) { + Object o = b.get("RESPONSE_CODE"); + if (o == null) { + //logDebug("Bundle with null response code, assuming OK (known issue)"); + return BILLING_RESPONSE_RESULT_OK; + } else if (o instanceof Integer) return ((Integer) o).intValue(); + else if (o instanceof Long) return (int) ((Long) o).longValue(); + else { + //logError("Unexpected type for bundle response code."); + //logError(o.getClass().getName()); + throw new RuntimeException("Unexpected type for bundle response code: " + o.getClass().getName()); + } + } + + /** + * Returns a human-readable description for the given response code. + * + * @param code The response code + * @return A human-readable string explaining the result code. + * It also includes the result code numerically. + */ + public static String getResponseDesc(int code) { + String[] iab_msgs = ("0:OK/1:User Canceled/2:Unknown/" + + "3:Billing Unavailable/4:Item unavailable/" + + "5:Developer Error/6:Error/7:Item Already Owned/" + + "8:Item not owned").split("/"); + String[] iabhelper_msgs = ("0:OK/-1001:Remote exception during initialization/" + + "-1002:Bad response received/" + + "-1003:Purchase signature verification failed/" + + "-1004:Send intent failed/" + + "-1005:User cancelled/" + + "-1006:Unknown purchase response/" + + "-1007:Missing token/" + + "-1008:Unknown error/" + + "-1009:Subscriptions not available/" + + "-1010:Invalid consumption attempt").split("/"); + + if (code <= -1000) { + int index = -1000 - code; + if (index >= 0 && index < iabhelper_msgs.length) return iabhelper_msgs[index]; + else return String.valueOf(code) + ":Unknown IAB Helper Error"; + } else if (code < 0 || code >= iab_msgs.length) + return String.valueOf(code) + ":Unknown"; + else + return iab_msgs[code]; + } + + public void querySkuDetails(final String[] list) { + (new Thread(new Runnable() { + @Override + public void run() { + ArrayList<String> skuList = new ArrayList<String>(Arrays.asList(list)); + if (skuList.size() == 0) { + return; + } + // Split the sku list in blocks of no more than 20 elements. + ArrayList<ArrayList<String>> packs = new ArrayList<ArrayList<String>>(); + ArrayList<String> tempList; + int n = skuList.size() / 20; + int mod = skuList.size() % 20; + for (int i = 0; i < n; i++) { + tempList = new ArrayList<String>(); + for (String s : skuList.subList(i * 20, i * 20 + 20)) { + tempList.add(s); + } + packs.add(tempList); + } + if (mod != 0) { + tempList = new ArrayList<String>(); + for (String s : skuList.subList(n * 20, n * 20 + mod)) { + tempList.add(s); + } + packs.add(tempList); + + for (ArrayList<String> skuPartList : packs) { + Bundle querySkus = new Bundle(); + querySkus.putStringArrayList("ITEM_ID_LIST", skuPartList); + Bundle skuDetails = null; + try { + skuDetails = mService.getSkuDetails(3, activity.getPackageName(), "inapp", querySkus); + if (!skuDetails.containsKey("DETAILS_LIST")) { + int response = getResponseCodeFromBundle(skuDetails); + if (response != BILLING_RESPONSE_RESULT_OK) { + godotPaymentV3.errorSkuDetail(getResponseDesc(response)); + } else { + godotPaymentV3.errorSkuDetail("No error but no detail list."); + } + return; + } + + ArrayList<String> responseList = skuDetails.getStringArrayList("DETAILS_LIST"); + + for (String thisResponse : responseList) { + Log.d("godot", "response = "+thisResponse); + godotPaymentV3.addSkuDetail(thisResponse); + } + } catch (RemoteException e) { + e.printStackTrace(); + godotPaymentV3.errorSkuDetail("RemoteException error!"); + } + } + godotPaymentV3.completeSkuDetail(); + } + } + })).start(); + } + private GodotPaymentV3 godotPaymentV3; - + public void setBaseSingleton(GodotPaymentV3 godotPaymentV3) { this.godotPaymentV3 = godotPaymentV3; } } - diff --git a/platform/android/java/src/org/godotengine/godot/payments/PurchaseTask.java b/platform/android/java/src/org/godotengine/godot/payments/PurchaseTask.java index 8b048d8065..5ad96b35ee 100644 --- a/platform/android/java/src/org/godotengine/godot/payments/PurchaseTask.java +++ b/platform/android/java/src/org/godotengine/godot/payments/PurchaseTask.java @@ -1,3 +1,31 @@ +/*************************************************************************/ +/* PurchaseTask.java */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 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 org.godotengine.godot.payments; import org.json.JSONException; @@ -35,18 +63,20 @@ abstract public class PurchaseTask { Log.d("XXX", "Starting purchase for: " + sku); PaymentsCache pc = new PaymentsCache(context); Boolean isBlocked = pc.getConsumableFlag("block", sku); -// if(isBlocked){ -// Log.d("XXX", "Is awaiting payment confirmation"); -// error("Awaiting payment confirmation"); -// return; -// } + /* + if(isBlocked){ + Log.d("XXX", "Is awaiting payment confirmation"); + error("Awaiting payment confirmation"); + return; + } + */ final String hash = transactionId; Bundle buyIntentBundle; try { buyIntentBundle = mService.getBuyIntent(3, context.getApplicationContext().getPackageName(), sku, "inapp", hash ); } catch (RemoteException e) { -// Log.d("XXX", "Error: " + e.getMessage()); + //Log.d("XXX", "Error: " + e.getMessage()); error(e.getMessage()); return; } @@ -59,7 +89,7 @@ abstract public class PurchaseTask { }else if( rc instanceof Long){ responseCode = (int)((Long)rc).longValue(); } -// Log.d("XXX", "Buy intent response code: " + responseCode); + //Log.d("XXX", "Buy intent response code: " + responseCode); if(responseCode == 1 || responseCode == 3 || responseCode == 4){ canceled(); return; @@ -74,12 +104,12 @@ abstract public class PurchaseTask { pc.setConsumableValue("validation_hash", sku, hash); try { if(context == null){ -// Log.d("XXX", "No context!"); + //Log.d("XXX", "No context!"); } if(pendingIntent == null){ -// Log.d("XXX", "No pending intent"); + //Log.d("XXX", "No pending intent"); } -// Log.d("XXX", "Starting activity for purchase!"); + //Log.d("XXX", "Starting activity for purchase!"); context.startIntentSenderForResult( pendingIntent.getIntentSender(), PaymentsManager.REQUEST_CODE_FOR_PURCHASE, diff --git a/platform/android/java/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java b/platform/android/java/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java index 7bb5131b49..60a43a9070 100644 --- a/platform/android/java/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java +++ b/platform/android/java/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java @@ -1,3 +1,31 @@ +/*************************************************************************/ +/* ReleaseAllConsumablesTask.java */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 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 org.godotengine.godot.payments; import java.util.ArrayList; @@ -28,13 +56,13 @@ abstract public class ReleaseAllConsumablesTask { public void consumeItAll(){ try{ -// Log.d("godot", "consumeItall for " + context.getPackageName()); + //Log.d("godot", "consumeItall for " + context.getPackageName()); Bundle bundle = mService.getPurchases(3, context.getPackageName(), "inapp",null); for (String key : bundle.keySet()) { - Object value = bundle.get(key); -// Log.d("godot", String.format("%s %s (%s)", key, -// value.toString(), value.getClass().getName())); + Object value = bundle.get(key); + //Log.d("godot", String.format("%s %s (%s)", key, + //value.toString(), value.getClass().getName())); } @@ -45,13 +73,13 @@ abstract public class ReleaseAllConsumablesTask { if (myPurchases == null || myPurchases.size() == 0){ -// Log.d("godot", "No purchases!"); + //Log.d("godot", "No purchases!"); notRequired(); return; } -// Log.d("godot", "# products to be consumed:" + myPurchases.size()); + //Log.d("godot", "# products to be consumed:" + myPurchases.size()); for (int i=0;i<myPurchases.size();i++) { @@ -61,7 +89,7 @@ abstract public class ReleaseAllConsumablesTask { String sku = inappPurchaseData.getString("productId"); String token = inappPurchaseData.getString("purchaseToken"); String signature = mySignatures.get(i); -// Log.d("godot", "A punto de consumir un item con token:" + token + "\n" + receipt); + //Log.d("godot", "A punto de consumir un item con token:" + token + "\n" + receipt); new GenericConsumeTask(context, mService, sku, receipt,signature, token) { @Override diff --git a/platform/android/java/src/org/godotengine/godot/payments/ValidateTask.java b/platform/android/java/src/org/godotengine/godot/payments/ValidateTask.java index 2fcf7483b4..f09bcbf9a4 100644 --- a/platform/android/java/src/org/godotengine/godot/payments/ValidateTask.java +++ b/platform/android/java/src/org/godotengine/godot/payments/ValidateTask.java @@ -1,3 +1,31 @@ +/*************************************************************************/ +/* ValidateTask.java */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 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 org.godotengine.godot.payments; import org.json.JSONException; @@ -51,14 +79,14 @@ abstract public class ValidateTask { param.put("ticket", pc.getConsumableValue("ticket", sku)); param.put("purchaseToken", pc.getConsumableValue("token", sku)); param.put("sku", sku); -// Log.d("XXX", "Haciendo request a " + url); -// Log.d("XXX", "ticket: " + pc.getConsumableValue("ticket", sku)); -// Log.d("XXX", "purchaseToken: " + pc.getConsumableValue("token", sku)); -// Log.d("XXX", "sku: " + sku); + //Log.d("XXX", "Haciendo request a " + url); + //Log.d("XXX", "ticket: " + pc.getConsumableValue("ticket", sku)); + //Log.d("XXX", "purchaseToken: " + pc.getConsumableValue("token", sku)); + //Log.d("XXX", "sku: " + sku); param.put("package", context.getApplicationContext().getPackageName()); HttpRequester requester = new HttpRequester(); String jsonResponse = requester.post(param); -// Log.d("XXX", "Validation response:\n"+jsonResponse); + //Log.d("XXX", "Validation response:\n"+jsonResponse); return jsonResponse; } diff --git a/platform/android/java/src/org/godotengine/godot/utils/Crypt.java b/platform/android/java/src/org/godotengine/godot/utils/Crypt.java index 2fb81cef8c..f8936bef2b 100644 --- a/platform/android/java/src/org/godotengine/godot/utils/Crypt.java +++ b/platform/android/java/src/org/godotengine/godot/utils/Crypt.java @@ -1,3 +1,31 @@ +/*************************************************************************/ +/* Crypt.java */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 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 org.godotengine.godot.utils; import java.security.MessageDigest; 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 2db88fcc9b..823c75d186 100644 --- a/platform/android/java/src/org/godotengine/godot/utils/CustomSSLSocketFactory.java +++ b/platform/android/java/src/org/godotengine/godot/utils/CustomSSLSocketFactory.java @@ -1,3 +1,31 @@ +/*************************************************************************/ +/* CustomSSLSocketFactory.java */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 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 org.godotengine.godot.utils; import java.io.IOException; import java.net.Socket; @@ -51,4 +79,4 @@ public class CustomSSLSocketFactory extends SSLSocketFactory { public Socket createSocket() throws IOException { return sslContext.getSocketFactory().createSocket(); } -}
\ No newline at end of file +} diff --git a/platform/android/java/src/org/godotengine/godot/utils/HttpRequester.java b/platform/android/java/src/org/godotengine/godot/utils/HttpRequester.java index 14346702cc..faefbbd2c6 100644 --- a/platform/android/java/src/org/godotengine/godot/utils/HttpRequester.java +++ b/platform/android/java/src/org/godotengine/godot/utils/HttpRequester.java @@ -1,3 +1,31 @@ +/*************************************************************************/ +/* HttpRequester.java */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 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 org.godotengine.godot.utils; import java.io.BufferedReader; @@ -50,12 +78,12 @@ public class HttpRequester { private long cttl=0; public HttpRequester(){ -// Log.d("XXX", "Creando http request sin contexto"); + //Log.d("XXX", "Creando http request sin contexto"); } public HttpRequester(Context context){ this.context=context; -// Log.d("XXX", "Creando http request con contexto"); + //Log.d("XXX", "Creando http request con contexto"); } public String post(RequestParams params){ @@ -71,7 +99,7 @@ public class HttpRequester { public String get(RequestParams params){ String response = getResponseFromCache(params.getUrl()); if(response == null){ -// Log.d("XXX", "Cache miss!"); + //Log.d("XXX", "Cache miss!"); HttpGet httpget = new HttpGet(params.getUrl()); long timeInit = new Date().getTime(); response = request(httpget); @@ -89,7 +117,7 @@ public class HttpRequester { } private String request(HttpUriRequest request){ -// Log.d("XXX", "Haciendo request a: " + request.getURI() ); + //Log.d("XXX", "Haciendo request a: " + request.getURI() ); Log.d("PPP", "Haciendo request a: " + request.getURI() ); long init = new Date().getTime(); HttpClient httpclient = getNewHttpClient(); @@ -100,10 +128,10 @@ public class HttpRequester { try { HttpResponse response = httpclient.execute(request); Log.d("PPP", "Fin de request (" + (new Date().getTime() - init) + ") a: " + request.getURI() ); -// Log.d("XXX1", "Status:" + response.getStatusLine().toString()); + //Log.d("XXX1", "Status:" + response.getStatusLine().toString()); if(response.getStatusLine().getStatusCode() == 200){ String strResponse = EntityUtils.toString(response.getEntity()); -// Log.d("XXX2", strResponse); + //Log.d("XXX2", strResponse); return strResponse; }else{ Log.d("XXX3", "Response status code:" + response.getStatusLine().getStatusCode() + "\n" + EntityUtils.toString(response.getEntity())); @@ -164,7 +192,7 @@ public class HttpRequester { public void saveResponseIntoCache(String request, String response){ if(context == null){ -// Log.d("XXX", "No context, cache failed!"); + //Log.d("XXX", "No context, cache failed!"); return; } SharedPreferences sharedPref = context.getSharedPreferences("http_get_cache", Context.MODE_PRIVATE); diff --git a/platform/android/java/src/org/godotengine/godot/utils/RequestParams.java b/platform/android/java/src/org/godotengine/godot/utils/RequestParams.java index 36753e368c..bb00f1f468 100644 --- a/platform/android/java/src/org/godotengine/godot/utils/RequestParams.java +++ b/platform/android/java/src/org/godotengine/godot/utils/RequestParams.java @@ -1,3 +1,31 @@ +/*************************************************************************/ +/* RequestParams.java */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 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 org.godotengine.godot.utils; import java.util.ArrayList; diff --git a/platform/android/java_bind.cpp b/platform/android/java_bind.cpp deleted file mode 100644 index 33ecfcffb6..0000000000 --- a/platform/android/java_bind.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "java_bind.h" - -JavaBind::JavaBind() -{ -} diff --git a/platform/android/java_bind.h b/platform/android/java_bind.h deleted file mode 100644 index ca6b4650d3..0000000000 --- a/platform/android/java_bind.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef JAVA_BIND_H -#define JAVA_BIND_H - -class JavaBind -{ -public: - JavaBind(); -}; - -#endif // JAVA_BIND_H diff --git a/platform/android/java_class_wrapper.cpp b/platform/android/java_class_wrapper.cpp index 283ea81152..9acda005f1 100644 --- a/platform/android/java_class_wrapper.cpp +++ b/platform/android/java_class_wrapper.cpp @@ -1,3 +1,31 @@ +/*************************************************************************/ +/* java_class_wrapper.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 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 "java_class_wrapper.h" #include "thread_jandroid.h" @@ -512,25 +540,21 @@ Variant JavaClass::call(const StringName& p_method,const Variant** p_args,int p_ JavaClass::JavaClass() { - } ///////////////////// Variant JavaObject::call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error){ - return Variant(); } JavaObject::JavaObject(const Ref<JavaClass>& p_base,jobject *p_instance) { - } JavaObject::~JavaObject(){ - } @@ -538,7 +562,7 @@ JavaObject::~JavaObject(){ void JavaClassWrapper::_bind_methods() { - ObjectTypeDB::bind_method(_MD("wrap:JavaClass","name"),&JavaClassWrapper::wrap); + ClassDB::bind_method(_MD("wrap:JavaClass","name"),&JavaClassWrapper::wrap); } @@ -1216,7 +1240,7 @@ Ref<JavaClass> JavaClassWrapper::wrap(const String& p_class) { //args[i] = _jobject_to_variant(env, obj); -// print_line("\targ"+itos(i)+": "+Variant::get_type_name(args[i].get_type())); + //print_line("\targ"+itos(i)+": "+Variant::get_type_name(args[i].get_type())); }; @@ -1328,5 +1352,4 @@ JavaClassWrapper::JavaClassWrapper(jobject p_activity) { bclass = env->FindClass("java/lang/Double"); Double_doubleValue = env->GetMethodID(bclass, "doubleValue", "()D"); - } diff --git a/platform/android/java_class_wrapper.h b/platform/android/java_class_wrapper.h index d5d8bd5be8..f0156563b2 100644 --- a/platform/android/java_class_wrapper.h +++ b/platform/android/java_class_wrapper.h @@ -1,3 +1,31 @@ +/*************************************************************************/ +/* java_class_wrapper.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 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 JAVA_CLASS_WRAPPER_H #define JAVA_CLASS_WRAPPER_H @@ -9,7 +37,7 @@ class JavaObject; class JavaClass : public Reference { - OBJ_TYPE(JavaClass,Reference); + GDCLASS(JavaClass,Reference); enum ArgumentType { @@ -70,14 +98,14 @@ class JavaClass : public Reference { case ARG_TYPE_CLASS: r_type=Variant::OBJECT; break; case ARG_ARRAY_BIT|ARG_TYPE_VOID: r_type=Variant::NIL; break; case ARG_ARRAY_BIT|ARG_TYPE_BOOLEAN: r_type=Variant::ARRAY; break; - case ARG_ARRAY_BIT|ARG_TYPE_BYTE: r_type=Variant::RAW_ARRAY; likelyhood=1.0; break; - case ARG_ARRAY_BIT|ARG_TYPE_CHAR: r_type=Variant::RAW_ARRAY; likelyhood=0.5; break; - case ARG_ARRAY_BIT|ARG_TYPE_SHORT: r_type=Variant::INT_ARRAY; likelyhood=0.3; break; - case ARG_ARRAY_BIT|ARG_TYPE_INT: r_type=Variant::INT_ARRAY; likelyhood=1.0; break; - case ARG_ARRAY_BIT|ARG_TYPE_LONG: r_type=Variant::INT_ARRAY; likelyhood=0.5; break; - case ARG_ARRAY_BIT|ARG_TYPE_FLOAT: r_type=Variant::REAL_ARRAY; likelyhood=1.0; break; - case ARG_ARRAY_BIT|ARG_TYPE_DOUBLE: r_type=Variant::REAL_ARRAY; likelyhood=0.5; break; - case ARG_ARRAY_BIT|ARG_TYPE_STRING: r_type=Variant::STRING_ARRAY; break; + case ARG_ARRAY_BIT|ARG_TYPE_BYTE: r_type=Variant::POOL_BYTE_ARRAY; likelyhood=1.0; break; + case ARG_ARRAY_BIT|ARG_TYPE_CHAR: r_type=Variant::POOL_BYTE_ARRAY; likelyhood=0.5; break; + case ARG_ARRAY_BIT|ARG_TYPE_SHORT: r_type=Variant::POOL_INT_ARRAY; likelyhood=0.3; break; + case ARG_ARRAY_BIT|ARG_TYPE_INT: r_type=Variant::POOL_INT_ARRAY; likelyhood=1.0; break; + case ARG_ARRAY_BIT|ARG_TYPE_LONG: r_type=Variant::POOL_INT_ARRAY; likelyhood=0.5; break; + case ARG_ARRAY_BIT|ARG_TYPE_FLOAT: r_type=Variant::POOL_REAL_ARRAY; likelyhood=1.0; break; + case ARG_ARRAY_BIT|ARG_TYPE_DOUBLE: r_type=Variant::POOL_REAL_ARRAY; likelyhood=0.5; break; + case ARG_ARRAY_BIT|ARG_TYPE_STRING: r_type=Variant::POOL_STRING_ARRAY; break; case ARG_ARRAY_BIT|ARG_TYPE_CLASS: r_type=Variant::ARRAY; break; } } @@ -103,7 +131,7 @@ public: class JavaObject : public Reference { - OBJ_TYPE(JavaObject,Reference); + GDCLASS(JavaObject,Reference); Ref<JavaClass> base_class; friend class JavaClass; @@ -122,7 +150,7 @@ public: class JavaClassWrapper : public Object { - OBJ_TYPE(JavaClassWrapper,Object); + GDCLASS(JavaClassWrapper,Object); Map<String,Ref<JavaClass> > class_cache; diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp index 1ea7cd7ebb..dfbb437344 100644 --- a/platform/android/java_glue.cpp +++ b/platform/android/java_glue.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 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 */ @@ -120,9 +120,9 @@ jvalret _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant* p_a v.val.l=jStr; v.obj=jStr; } break; - case Variant::STRING_ARRAY: { + case Variant::POOL_STRING_ARRAY: { - DVector<String> sarray = *p_arg; + PoolVector<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++) { @@ -179,30 +179,30 @@ jvalret _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant* p_a v.obj=jdict; } break; - case Variant::INT_ARRAY: { + case Variant::POOL_INT_ARRAY: { - DVector<int> array = *p_arg; + PoolVector<int> array = *p_arg; jintArray arr = env->NewIntArray(array.size()); - DVector<int>::Read r = array.read(); + PoolVector<int>::Read r = array.read(); env->SetIntArrayRegion(arr,0,array.size(),r.ptr()); v.val.l=arr; v.obj=arr; } break; - case Variant::RAW_ARRAY: { - DVector<uint8_t> array = *p_arg; + case Variant::POOL_BYTE_ARRAY: { + PoolVector<uint8_t> array = *p_arg; jbyteArray arr = env->NewByteArray(array.size()); - DVector<uint8_t>::Read r = array.read(); + PoolVector<uint8_t>::Read r = array.read(); env->SetByteArrayRegion(arr,0,array.size(),reinterpret_cast<const signed char*>(r.ptr())); v.val.l=arr; v.obj=arr; } break; - case Variant::REAL_ARRAY: { + case Variant::POOL_REAL_ARRAY: { - DVector<float> array = *p_arg; + PoolVector<float> array = *p_arg; jfloatArray arr = env->NewFloatArray(array.size()); - DVector<float>::Read r = array.read(); + PoolVector<float>::Read r = array.read(); env->SetFloatArrayRegion(arr,0,array.size(),r.ptr()); v.val.l=arr; v.obj=arr; @@ -215,7 +215,7 @@ jvalret _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant* p_a } return v; -}; +} String _get_class_name(JNIEnv * env, jclass cls, bool* array) { @@ -233,11 +233,15 @@ String _get_class_name(JNIEnv * env, jclass cls, bool* array) { return name; -}; +} Variant _jobject_to_variant(JNIEnv * env, jobject obj) { + if (obj == NULL) { + return Variant(); + } + jclass c = env->GetObjectClass(obj); bool array; String name = _get_class_name(env, c, &array); @@ -255,12 +259,11 @@ Variant _jobject_to_variant(JNIEnv * env, jobject obj) { jobjectArray arr = (jobjectArray)obj; int stringCount = env->GetArrayLength(arr); //print_line("String array! " + String::num(stringCount)); - DVector<String> sarr; + PoolVector<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)); + sarr.push_back(String::utf8(env->GetStringUTFChars(string, NULL))); env->DeleteLocalRef(string); } @@ -287,12 +290,12 @@ Variant _jobject_to_variant(JNIEnv * env, jobject obj) { jintArray arr = (jintArray)obj; int fCount = env->GetArrayLength(arr); - DVector<int> sarr; + PoolVector<int> sarr; sarr.resize(fCount); - DVector<int>::Write w = sarr.write(); + PoolVector<int>::Write w = sarr.write(); env->GetIntArrayRegion(arr,0,fCount,w.ptr()); - w = DVector<int>::Write(); + w = PoolVector<int>::Write(); return sarr; }; @@ -300,12 +303,12 @@ Variant _jobject_to_variant(JNIEnv * env, jobject obj) { jbyteArray arr = (jbyteArray)obj; int fCount = env->GetArrayLength(arr); - DVector<uint8_t> sarr; + PoolVector<uint8_t> sarr; sarr.resize(fCount); - DVector<uint8_t>::Write w = sarr.write(); + PoolVector<uint8_t>::Write w = sarr.write(); env->GetByteArrayRegion(arr,0,fCount,reinterpret_cast<signed char*>(w.ptr())); - w = DVector<uint8_t>::Write(); + w = PoolVector<uint8_t>::Write(); return sarr; }; @@ -321,10 +324,10 @@ Variant _jobject_to_variant(JNIEnv * env, jobject obj) { jdoubleArray arr = (jdoubleArray)obj; int fCount = env->GetArrayLength(arr); - RealArray sarr; + PoolRealArray sarr; sarr.resize(fCount); - RealArray::Write w = sarr.write(); + PoolRealArray::Write w = sarr.write(); for (int i=0; i<fCount; i++) { @@ -340,11 +343,11 @@ Variant _jobject_to_variant(JNIEnv * env, jobject obj) { jfloatArray arr = (jfloatArray)obj; int fCount = env->GetArrayLength(arr); - RealArray sarr; + PoolRealArray sarr; sarr.resize(fCount); - RealArray::Write w = sarr.write(); + PoolRealArray::Write w = sarr.write(); for (int i=0; i<fCount; i++) { @@ -381,7 +384,7 @@ Variant _jobject_to_variant(JNIEnv * env, jobject obj) { 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); + PoolStringArray keys = _jobject_to_variant(env, arr); env->DeleteLocalRef(arr); jmethodID get_values = env->GetMethodID(oclass, "get_values", "()[Ljava/lang/Object;"); @@ -403,11 +406,11 @@ Variant _jobject_to_variant(JNIEnv * env, jobject obj) { env->DeleteLocalRef(c); return Variant(); -}; +} class JNISingleton : public Object { - OBJ_TYPE( JNISingleton, Object ); + GDCLASS( JNISingleton, Object ); struct MethodData { @@ -506,7 +509,7 @@ public: } break; case Variant::BOOL: { - ret = env->CallBooleanMethodA(instance,E->get().method,v); + ret = env->CallBooleanMethodA(instance,E->get().method,v)==JNI_TRUE; //print_line("call bool"); } break; case Variant::INT: { @@ -521,11 +524,10 @@ public: case Variant::STRING: { jobject o = env->CallObjectMethodA(instance,E->get().method,v); - String str = env->GetStringUTFChars((jstring)o, NULL ); - ret=str; + ret = String::utf8(env->GetStringUTFChars((jstring)o, NULL)); env->DeleteLocalRef(o); } break; - case Variant::STRING_ARRAY: { + case Variant::POOL_STRING_ARRAY: { jobjectArray arr = (jobjectArray)env->CallObjectMethodA(instance,E->get().method,v); @@ -533,31 +535,31 @@ public: env->DeleteLocalRef(arr); } break; - case Variant::INT_ARRAY: { + case Variant::POOL_INT_ARRAY: { jintArray arr = (jintArray)env->CallObjectMethodA(instance,E->get().method,v); int fCount = env->GetArrayLength(arr); - DVector<int> sarr; + PoolVector<int> sarr; sarr.resize(fCount); - DVector<int>::Write w = sarr.write(); + PoolVector<int>::Write w = sarr.write(); env->GetIntArrayRegion(arr,0,fCount,w.ptr()); - w = DVector<int>::Write(); + w = PoolVector<int>::Write(); ret=sarr; env->DeleteLocalRef(arr); } break; - case Variant::REAL_ARRAY: { + case Variant::POOL_REAL_ARRAY: { jfloatArray arr = (jfloatArray)env->CallObjectMethodA(instance,E->get().method,v); int fCount = env->GetArrayLength(arr); - DVector<float> sarr; + PoolVector<float> sarr; sarr.resize(fCount); - DVector<float>::Write w = sarr.write(); + PoolVector<float>::Write w = sarr.write(); env->GetFloatArrayRegion(arr,0,fCount,w.ptr()); - w = DVector<float>::Write(); + w = PoolVector<float>::Write(); ret=sarr; env->DeleteLocalRef(arr); } break; @@ -640,17 +642,18 @@ struct JAndroidPointerEvent { static List<JAndroidPointerEvent> pointer_events; static List<InputEvent> key_events; -static List<OS_Android::JoystickEvent> joy_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 quit_request=false; +static bool go_back_request=false; static Size2 new_size; static Vector3 accelerometer; static Vector3 magnetometer; +static Vector3 gyroscope; static HashMap<String,JNISingleton*> jni_singletons; static jobject godot_io; @@ -665,6 +668,7 @@ static jmethodID _openURI=0; static jmethodID _getDataDir=0; static jmethodID _getLocale=0; static jmethodID _getModel=0; +static jmethodID _getScreenDPI=0; static jmethodID _showKeyboard=0; static jmethodID _hideKeyboard=0; static jmethodID _setScreenOrientation=0; @@ -675,6 +679,7 @@ static jmethodID _isVideoPlaying=0; static jmethodID _pauseVideo=0; static jmethodID _stopVideo=0; static jmethodID _setKeepScreenOn=0; +static jmethodID _alertDialog=0; static void _gfx_init_func(void* ud, bool gl2) { @@ -709,6 +714,12 @@ static String _get_model() { return String(env->GetStringUTFChars( s, NULL )); } +static int _get_screen_dpi() { + + JNIEnv *env = ThreadAndroid::get_env(); + return env->CallIntMethod(godot_io,_getScreenDPI); +} + static String _get_unique_id() { JNIEnv *env = ThreadAndroid::get_env(); @@ -721,27 +732,27 @@ 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 String _get_system_dir(int p_dir) { JNIEnv *env = ThreadAndroid::get_env(); jstring s =(jstring)env->CallObjectMethod(godot_io,_getSystemDir,p_dir); return String(env->GetStringUTFChars( s, NULL )); -}; +} static void _hide_vk() { JNIEnv* env = ThreadAndroid::get_env(); env->CallVoidMethod(godot_io, _hideKeyboard); -}; +} // virtual Error native_video_play(String p_path); // virtual bool native_video_is_playing(); @@ -773,6 +784,13 @@ static void _set_keep_screen_on(bool p_enabled) { env->CallVoidMethod(_godot_instance, _setKeepScreenOn, p_enabled); } +static void _alert(const String& p_message, const String& p_title) { + JNIEnv* env = ThreadAndroid::get_env(); + jstring jStrMessage = env->NewStringUTF(p_message.utf8().get_data()); + jstring jStrTitle = env->NewStringUTF(p_title.utf8().get_data()); + 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) { __android_log_print(ANDROID_LOG_INFO,"godot","**INIT EVENT! - %p\n",env); @@ -784,7 +802,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv * e env->GetJavaVM(&jvm); _godot_instance=env->NewGlobalRef(activity); -// _godot_instance=activity; + //_godot_instance=activity; __android_log_print(ANDROID_LOG_INFO,"godot","***************** HELLO FROM JNI!!!!!!!!"); @@ -810,6 +828,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv * e _on_video_init = env->GetMethodID(cls, "onVideoInit", "(Z)V"); _setKeepScreenOn = env->GetMethodID(cls,"setKeepScreenOn","(Z)V"); + _alertDialog = env->GetMethodID(cls,"alert","(Ljava/lang/String;Ljava/lang/String;)V"); jclass clsio = env->FindClass("org/godotengine/godot/Godot"); if (cls) { @@ -818,6 +837,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv * e _getDataDir = env->GetMethodID(c,"getDataDir","()Ljava/lang/String;"); _getLocale = env->GetMethodID(c,"getLocale","()Ljava/lang/String;"); _getModel = env->GetMethodID(c,"getModel","()Ljava/lang/String;"); + _getScreenDPI = env->GetMethodID(c, "getScreenDPI","()I"); _getUniqueID = env->GetMethodID(c,"getUniqueID","()Ljava/lang/String;"); _showKeyboard = env->GetMethodID(c,"showKeyboard","(Ljava/lang/String;)V"); _hideKeyboard = env->GetMethodID(c,"hideKeyboard","()V"); @@ -859,7 +879,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv * e 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); + //__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; @@ -872,7 +892,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv * e __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,_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, 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->set_need_reload_hooks(p_need_reload_hook); char wd[500]; @@ -901,7 +921,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv * e __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"); + String vd = GlobalConfig::get_singleton()->get("display/driver"); env->CallVoidMethod(_godot_instance, _on_video_init, (jboolean)true); @@ -942,23 +962,20 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv * e os_android->reload_gfx(); } - } -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_quit(JNIEnv * env, jobject obj) { +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv * env, jobject obj) { input_mutex->lock(); - quit_request=true; - print_line("BACK PRESSED"); + go_back_request=true; input_mutex->unlock(); } static void _initialize_java_modules() { - - String modules = Globals::get_singleton()->get("android/modules"); + String modules = GlobalConfig::get_singleton()->get("android/modules"); Vector<String> mods = modules.split(",",false); print_line("ANDROID MODULES : " + modules); __android_log_print(ANDROID_LOG_INFO,"godot","mod count: %i",mods.size()); @@ -1033,7 +1050,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv * env, jo // because of the way android forces you to do everything with threads java_class_wrapper = memnew( JavaClassWrapper(_godot_instance )); - Globals::get_singleton()->add_singleton(Globals::Singleton("JavaClassWrapper",java_class_wrapper)); + GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("JavaClassWrapper",java_class_wrapper)); _initialize_java_modules(); Main::setup2(); @@ -1072,16 +1089,16 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv * env, jo while (joy_events.size()) { - OS_Android::JoystickEvent event = joy_events.front()->get(); + OS_Android::JoypadEvent event = joy_events.front()->get(); os_android->process_joy_event(event); joy_events.pop_front(); } - if (quit_request) { + if (go_back_request) { - os_android->main_loop_request_quit(); - quit_request=false; + os_android->main_loop_request_go_back(); + go_back_request=false; } @@ -1091,6 +1108,8 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv * env, jo os_android->process_magnetometer(magnetometer); + os_android->process_gyroscope(gyroscope); + if (os_android->main_loop_iterate()==true) { jclass cls = env->FindClass("org/godotengine/godot/Godot"); @@ -1132,8 +1151,10 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch(JNIEnv * env, j pointer_events.push_back(jpe); input_mutex->unlock(); - //if (os_android) -// os_android->process_touch(ev,pointer,points); + /* + if (os_android) + os_android->process_touch(ev,pointer,points); + */ } @@ -1395,7 +1416,7 @@ static unsigned int android_get_keysym(unsigned int p_code) { JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv * env, jobject obj, jint p_device, jint p_button, jboolean p_pressed) { - OS_Android::JoystickEvent jevent; + OS_Android::JoypadEvent jevent; jevent.device = p_device; jevent.type = OS_Android::JOY_EVENT_BUTTON; jevent.index = p_button; @@ -1404,11 +1425,11 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv * en input_mutex->lock(); joy_events.push_back(jevent); input_mutex->unlock(); -}; +} JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv * env, jobject obj, jint p_device, jint p_axis, jfloat p_value) { - OS_Android::JoystickEvent jevent; + OS_Android::JoypadEvent jevent; jevent.device = p_device; jevent.type = OS_Android::JOY_EVENT_AXIS; jevent.index = p_axis; @@ -1417,10 +1438,10 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv * env, input_mutex->lock(); joy_events.push_back(jevent); input_mutex->unlock(); -}; +} JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv * env, jobject obj, jint p_device, jint p_hat_x, jint p_hat_y) { - OS_Android::JoystickEvent jevent; + OS_Android::JoypadEvent jevent; jevent.device = p_device; jevent.type = OS_Android::JOY_EVENT_HAT; int hat = 0; @@ -1474,13 +1495,13 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv * env, job ievent.key.unicode = KEY_ENTER; } else if (p_scancode==4) { - quit_request=true; + go_back_request=true; } input_mutex->lock(); key_events.push_back(ievent); input_mutex->unlock(); -}; +} JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv * env, jobject obj, jfloat x, jfloat y, jfloat z) { @@ -1499,6 +1520,14 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_magnetometer(JNIEnv * } +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) @@ -1542,8 +1571,8 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_singleton(JNIEnv * en 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); + GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton(singname,s)); + GlobalConfig::get_singleton()->set(singname,s); } @@ -1560,10 +1589,10 @@ static Variant::Type get_jni_type(const String& p_type) { {"float",Variant::REAL}, {"double", Variant::REAL}, {"java.lang.String",Variant::STRING}, - {"[I",Variant::INT_ARRAY}, - {"[B",Variant::RAW_ARRAY}, - {"[F",Variant::REAL_ARRAY}, - {"[java.lang.String",Variant::STRING_ARRAY}, + {"[I",Variant::POOL_INT_ARRAY}, + {"[B",Variant::POOL_BYTE_ARRAY}, + {"[F",Variant::POOL_REAL_ARRAY}, + {"[Ljava.lang.String;",Variant::POOL_STRING_ARRAY}, {"org.godotengine.godot.Dictionary", Variant::DICTIONARY}, {NULL,Variant::NIL} }; @@ -1599,7 +1628,7 @@ static const char* get_jni_sig(const String& p_type) { {"[I","[I"}, {"[B","[B"}, {"[F","[F"}, - {"[java.lang.String","[Ljava/lang/String;"}, + {"[Ljava.lang.String;","[Ljava/lang/String;"}, {NULL,"V"} }; @@ -1621,7 +1650,7 @@ JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getGlobal(JNIEnv * String js = env->GetStringUTFChars( path, NULL ); - return env->NewStringUTF(Globals::get_singleton()->get(js).operator String().utf8().get_data()); + return env->NewStringUTF(GlobalConfig::get_singleton()->get(js).operator String().utf8().get_data()); } @@ -1701,7 +1730,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv * e env->PopLocalFrame(NULL); -}; +} JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv * env, jobject p_obj, jint ID, jstring method, jobjectArray params) { @@ -1726,7 +1755,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv * args[i] = _jobject_to_variant(env, obj); env->DeleteLocalRef(obj); -// print_line("\targ"+itos(i)+": "+Variant::get_type_name(args[i].get_type())); + //print_line("\targ"+itos(i)+": "+Variant::get_type_name(args[i].get_type())); }; @@ -1736,7 +1765,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv * // something env->PopLocalFrame(NULL); -}; +} //Main::cleanup(); diff --git a/platform/android/java_glue.h b/platform/android/java_glue.h index f7916efe2c..bc4628b9d4 100644 --- a/platform/android/java_glue.h +++ b/platform/android/java_glue.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 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 */ @@ -50,6 +50,7 @@ extern "C" { JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_audio(JNIEnv * env, jobject obj); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv * env, jobject obj, jfloat x, jfloat y, jfloat z); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_magnetometer(JNIEnv * env, jobject obj, jfloat x, jfloat y, jfloat z); + JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gyroscope(JNIEnv * env, jobject obj, jfloat x, jfloat y, jfloat z); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusin(JNIEnv * env, jobject obj); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusout(JNIEnv * env, jobject obj); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_singleton(JNIEnv * env, jobject obj, jstring name,jobject p_object); @@ -57,7 +58,7 @@ extern "C" { 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 obj, jint ID, jstring method, jobjectArray params); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv * env, jobject obj, jint ID, jstring method, jobjectArray params); -}; +} #endif diff --git a/platform/android/logo.png b/platform/android/logo.png Binary files differindex a7e2c6f130..fcf684c026 100644 --- a/platform/android/logo.png +++ b/platform/android/logo.png diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 4e6dfb2db2..562666b679 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 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 */ @@ -53,6 +53,7 @@ int OS_Android::get_video_driver_count() const { return 1; } + const char * OS_Android::get_video_driver_name(int p_driver) const { return "GLES2"; @@ -131,15 +132,10 @@ void OS_Android::initialize(const VideoMode& p_desired,int p_video_driver,int p_ AudioDriverManagerSW::add_driver(&audio_driver_android); - if (true) { - 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) ); - - } + 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; rasterizer->set_force_16_bits_fbo(use_16bits_fbo); @@ -250,9 +246,11 @@ void OS_Android::print(const char *p_format, ... ) { } -void OS_Android::alert(const String& p_alert) { +void OS_Android::alert(const String& p_alert,const String& p_title) { print("ALERT: %s\n",p_alert.utf8().get_data()); + if (alert_func) + alert_func(p_alert, p_title); } @@ -271,17 +269,18 @@ 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 @@ -290,13 +289,13 @@ void OS_Android::set_window_title(const String& p_title) { 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); @@ -340,6 +339,7 @@ void OS_Android::main_loop_begin() { if (main_loop) main_loop->init(); } + bool OS_Android::main_loop_iterate() { if (!main_loop) @@ -370,7 +370,7 @@ void OS_Android::main_loop_focusin(){ } -void OS_Android::process_joy_event(OS_Android::JoystickEvent p_event) { +void OS_Android::process_joy_event(OS_Android::JoypadEvent p_event) { switch (p_event.type) { case JOY_EVENT_BUTTON: @@ -394,12 +394,12 @@ 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())); + //print_line("ev: "+itos(p_what)+" pnt: "+itos(p_pointer)+" pointc: "+itos(p_points.size())); switch(p_what) { case 0: { //gesture begin @@ -482,8 +482,8 @@ void OS_Android::process_touch(int p_what,int p_pointer, const Vector<TouchPos>& 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.speed_x=input->get_last_mouse_speed().x; + ev.mouse_motion.speed_y=input->get_last_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; @@ -614,6 +614,11 @@ void OS_Android::process_magnetometer(const Vector3& p_magnetometer) { input->set_magnetometer(p_magnetometer); } +void OS_Android::process_gyroscope(const Vector3& p_gyroscope) { + + input->set_gyroscope(p_gyroscope); +} + bool OS_Android::has_touchscreen_ui_hint() const { return true; @@ -622,7 +627,7 @@ bool OS_Android::has_touchscreen_ui_hint() const { 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) { @@ -632,7 +637,7 @@ void OS_Android::show_virtual_keyboard(const String& p_existing_text,const Rect2 ERR_PRINT("Virtual keyboard not available"); }; -}; +} void OS_Android::hide_virtual_keyboard() { @@ -643,7 +648,7 @@ void OS_Android::hide_virtual_keyboard() { ERR_PRINT("Virtual keyboard not available"); }; -}; +} void OS_Android::init_video_mode(int p_video_width,int p_video_height) { @@ -654,10 +659,10 @@ void OS_Android::init_video_mode(int p_video_width,int p_video_height) { default_videomode.resizable=false; } -void OS_Android::main_loop_request_quit() { +void OS_Android::main_loop_request_go_back() { if (main_loop) - main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST); + main_loop->notification(MainLoop::NOTIFICATION_WM_GO_BACK_REQUEST); } void OS_Android::set_display_size(Size2 p_size) { @@ -679,7 +684,7 @@ 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 { @@ -700,6 +705,13 @@ String OS_Android::get_model_name() const { return OS_Unix::get_model_name(); } +int OS_Android::get_screen_dpi(int p_screen) const { + + if (get_screen_dpi_func) { + return get_screen_dpi_func(); + } + return 160; +} void OS_Android::set_need_reload_hooks(bool p_needs_them) { @@ -708,16 +720,40 @@ void OS_Android::set_need_reload_hooks(bool p_needs_them) { String OS_Android::get_data_dir() const { - if (get_data_dir_func) - return get_data_dir_func(); + if (data_dir_cache!=String()) + return data_dir_cache; + + if (get_data_dir_func) { + String data_dir=get_data_dir_func(); + + //store current dir + char real_current_dir_name[2048]; + getcwd(real_current_dir_name,2048); + + //go to data dir + chdir(data_dir.utf8().get_data()); + + //get actual data dir, so we resolve potential symlink (Android 6.0+ seems to use symlink) + char data_current_dir_name[2048]; + getcwd(data_current_dir_name,2048); + + //cache by parsing utf8 + data_dir_cache.parse_utf8(data_current_dir_name); + + //restore original dir so we don't mess things up + chdir(real_current_dir_name); + + return data_dir_cache; + } + + return "."; - //return Globals::get_singleton()->get_singleton_object("GodotOS")->call("get_data_dir"); -}; + //return GlobalConfig::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); } @@ -778,8 +814,7 @@ String OS_Android::get_joy_guid(int p_device) const { return input->get_joy_guid_remapped(p_device); } -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,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, 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, 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; @@ -799,6 +834,7 @@ OS_Android::OS_Android(GFXInitFunc p_gfx_init_func,void*p_gfx_init_ud, OpenURIFu get_data_dir_func=p_get_data_dir_func; get_locale_func=p_get_locale_func; get_model_func=p_get_model_func; + get_screen_dpi_func = p_get_screen_dpi_func; get_unique_id_func=p_get_unique_id; get_system_dir_func=p_get_sdir_func; @@ -812,11 +848,11 @@ OS_Android::OS_Android(GFXInitFunc p_gfx_init_func,void*p_gfx_init_ud, OpenURIFu 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; } OS_Android::~OS_Android() { - } diff --git a/platform/android/os_android.h b/platform/android/os_android.h index 843b3c4788..9ed7ba5fac 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 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 */ @@ -63,6 +63,7 @@ typedef int (*OpenURIFunc)(const String&); typedef String (*GetDataDirFunc)(); typedef String (*GetLocaleFunc)(); typedef String (*GetModelFunc)(); +typedef int (*GetScreenDPIFunc)(); typedef String (*GetUniqueIDFunc)(); typedef void (*ShowVirtualKeyboardFunc)(const String&); typedef void (*HideVirtualKeyboardFunc)(); @@ -74,6 +75,7 @@ typedef bool (*VideoIsPlayingFunc)(); typedef void (*VideoPauseFunc)(); typedef void (*VideoStopFunc)(); typedef void (*SetKeepScreenOnFunc)(bool p_enabled); +typedef void (*AlertFunc)(const String&, const String&); class OS_Android : public OS_Unix { public: @@ -89,7 +91,7 @@ public: JOY_EVENT_HAT = 2 }; - struct JoystickEvent { + struct JoypadEvent { int device; int type; @@ -123,6 +125,8 @@ private: PhysicsServer *physics_server; Physics2DServer *physics_2d_server; + mutable String data_dir_cache; + #if 0 AudioDriverAndroid audio_driver_android; #else @@ -139,6 +143,7 @@ private: GetDataDirFunc get_data_dir_func; GetLocaleFunc get_locale_func; GetModelFunc get_model_func; + GetScreenDPIFunc get_screen_dpi_func; ShowVirtualKeyboardFunc show_virtual_keyboard_func; HideVirtualKeyboardFunc hide_virtual_keyboard_func; SetScreenOrientationFunc set_screen_orientation_func; @@ -150,6 +155,7 @@ private: VideoPauseFunc video_pause_func; VideoStopFunc video_stop_func; SetKeepScreenOnFunc set_keep_screen_on_func; + AlertFunc alert_func; public: @@ -177,7 +183,7 @@ public: 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 alert(const String& p_alert,const String& p_title="ALERT!"); virtual void set_mouse_show(bool p_show); @@ -207,7 +213,7 @@ public: void main_loop_begin(); bool main_loop_iterate(); - void main_loop_request_quit(); + void main_loop_request_go_back(); void main_loop_end(); void main_loop_focusout(); void main_loop_focusin(); @@ -232,6 +238,7 @@ public: virtual String get_resource_dir() const; virtual String get_locale() const; virtual String get_model_name() const; + virtual int get_screen_dpi(int p_screen=0) const; virtual String get_unique_ID() const; @@ -240,8 +247,9 @@ public: void process_accelerometer(const Vector3& p_accelerometer); void process_magnetometer(const Vector3& p_magnetometer); + void process_gyroscope(const Vector3& p_gyroscope); void process_touch(int p_what,int p_pointer, const Vector<TouchPos>& p_points); - void process_joy_event(JoystickEvent p_event); + void process_joy_event(JoypadEvent p_event); void process_event(InputEvent p_event); void init_video_mode(int p_video_width,int p_video_height); @@ -254,7 +262,7 @@ public: virtual String get_joy_guid(int p_device) const; void joy_connection_changed(int p_device, bool p_connected, String p_name); - 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,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, 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, 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/platform_config.h b/platform/android/platform_config.h index 143f16c1fa..cdef185ff0 100644 --- a/platform/android/platform_config.h +++ b/platform/android/platform_config.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 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 */ diff --git a/platform/android/thread_jandroid.cpp b/platform/android/thread_jandroid.cpp index 1425e23c73..aa40d995d9 100644 --- a/platform/android/thread_jandroid.cpp +++ b/platform/android/thread_jandroid.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 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 */ @@ -29,6 +29,7 @@ #include "thread_jandroid.h" #include "os/memory.h" +#include "script_language.h" Thread::ID ThreadAndroid::get_ID() const { @@ -44,8 +45,10 @@ void *ThreadAndroid::thread_callback(void *userdata) { ThreadAndroid *t=reinterpret_cast<ThreadAndroid*>(userdata); setup_thread(); + ScriptServer::thread_enter(); //scripts may need to attach a stack t->id=(ID)pthread_self(); t->callback(t->user); + ScriptServer::thread_exit(); return NULL; } @@ -61,10 +64,12 @@ Thread* ThreadAndroid::create_func_jandroid(ThreadCreateCallback p_callback,void 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); diff --git a/platform/android/thread_jandroid.h b/platform/android/thread_jandroid.h index c8ad6c8735..6f52b730f1 100644 --- a/platform/android/thread_jandroid.h +++ b/platform/android/thread_jandroid.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 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 */ |