diff --git a/backends/platform/android/asset-archive.cpp b/backends/platform/android/asset-archive.cpp index 255262d3098..76c3588935f 100644 --- a/backends/platform/android/asset-archive.cpp +++ b/backends/platform/android/asset-archive.cpp @@ -132,15 +132,23 @@ int AndroidAssetArchive::listMembers(Common::ArchiveMemberList &member_list) con } int count = 0; - AAssetDir *dir = AAssetManager_openDir(_am, ""); - const char *file = AAssetDir_getNextFileName(dir); + Common::List dirs; + dirs.push_back(""); +#ifdef BACKEND_ANDROID3D + // ResidualVM specific: multiple directories + dirs.push_back("shaders"); +#endif + for (const auto& currentDir : dirs) { + AAssetDir *dir = AAssetManager_openDir(_am, ""); + const char *file = AAssetDir_getNextFileName(dir); - while (file) { - member_list.push_back(getMember(file)); - ++count; - file = AAssetDir_getNextFileName(dir); + while (file) { + member_list.push_back(getMember(currentDir + Common::String(file))); + ++count; + file = AAssetDir_getNextFileName(dir); + } + AAssetDir_close(dir); } - AAssetDir_close(dir); _cachedMembers = Common::ArchiveMemberList(member_list); _hasCached = true; diff --git a/backends/platform/android/jni-android.cpp b/backends/platform/android/jni-android.cpp index bf8d14493d2..0855f7fb10a 100644 --- a/backends/platform/android/jni-android.cpp +++ b/backends/platform/android/jni-android.cpp @@ -137,7 +137,11 @@ jint JNI::onLoad(JavaVM *vm) { if (_vm->GetEnv((void **)&env, JNI_VERSION_1_2)) return JNI_ERR; +#ifdef BACKEND_ANDROID3D + jclass cls = env->FindClass("org/residualvm/residualvm/ResidualVM"); +#else jclass cls = env->FindClass("org/scummvm/scummvm/ScummVM"); +#endif if (cls == 0) return JNI_ERR; @@ -732,10 +736,12 @@ void JNI::setPause(JNIEnv *env, jobject self, jboolean value) { else JNI::_pauseToken.clear(); - /*if (value && +#ifdef BACKEND_ANDROID3D + if (value && g_engine->hasFeature(Engine::kSupportsSavingDuringRuntime) && g_engine->canSaveGameStateCurrently()) - g_engine->saveGameState(0, "Android parachute");*/ + g_engine->saveGameState(0, "Android parachute"); +#endif } pause = value; diff --git a/backends/platform/android3d/asset-archive.cpp b/backends/platform/android3d/asset-archive.cpp index cb5a332bdaa..db57f1ff491 100644 --- a/backends/platform/android3d/asset-archive.cpp +++ b/backends/platform/android3d/asset-archive.cpp @@ -1,168 +1,2 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#if defined(__ANDROID__) - -#include -#include - -#include "common/str.h" -#include "common/stream.h" -#include "common/util.h" -#include "common/archive.h" -#include "common/debug.h" -#include "common/textconsole.h" - -#include "backends/platform/android3d/jni-android.h" -#include "backends/platform/android3d/asset-archive.h" - -#include -#include - -class AssetInputStream : public Common::SeekableReadStream { -public: - AssetInputStream(AAssetManager *as, const Common::String &path); - virtual ~AssetInputStream(); - - virtual bool eos() const { return _eos; } - - virtual void clearErr() {_eos = false; } - - virtual uint32 read(void *dataPtr, uint32 dataSize); - - virtual int32 pos() const { return _pos; } - - virtual int32 size() const { return _len; } - - virtual bool seek(int32 offset, int whence = SEEK_SET); - -private: - void close(); - AAsset *_asset; - - uint32 _pos; - uint32 _len; - bool _eos; -}; - -AssetInputStream::AssetInputStream(AAssetManager *as, const Common::String &path) : - _eos(false), _pos(0) { - _asset = AAssetManager_open(as, path.c_str(), AASSET_MODE_RANDOM); - _len = AAsset_getLength(_asset); -} - -AssetInputStream::~AssetInputStream() { - if (_asset != NULL) { - AAsset_close(_asset); - } -} - -void AssetInputStream::close() { - AAsset_close(_asset); -} - -uint32 AssetInputStream::read(void *dataPtr, uint32 dataSize) { - uint32 readlen = AAsset_read(_asset, dataPtr, dataSize); - _pos += readlen; - if (readlen != dataSize) { - _eos = true; - } - return readlen; -} - -bool AssetInputStream::seek(int32 offset, int whence) { - int res = AAsset_seek(_asset, offset, whence); - if (res == -1) { - return false; - } - if (whence == SEEK_CUR) { - _pos += offset; - } else if (whence == SEEK_SET) { - _pos = offset; - } else if (whence == SEEK_END) { - _pos = _len + offset; - } - assert(_pos <= _len); - _eos = false; - return true; -} - -AndroidAssetArchive::AndroidAssetArchive(jobject am) : _hasCached(false) { - JNIEnv *env = JNI::getEnv(); - - _am = AAssetManager_fromJava(env, am); -} - -AndroidAssetArchive::~AndroidAssetArchive() { -} - -bool AndroidAssetArchive::hasFile(const Common::String &name) const { - AAsset *asset = AAssetManager_open(_am, name.c_str(), AASSET_MODE_RANDOM); - bool exists = false; - if (asset != NULL) { - exists = true; - AAsset_close(asset); - } - return exists; -} - -int AndroidAssetArchive::listMembers(Common::ArchiveMemberList &member_list) const { - if (_hasCached) { - member_list.insert(member_list.end(), _cachedMembers.begin(), _cachedMembers.end()); - return _cachedMembers.size(); - } - - // ResidualVM specific: multiple directories - Common::List dirs; - dirs.push_back(""); - dirs.push_back("shaders"); - int count = 0; - for (const auto& currentDir : dirs) { - AAssetDir *dir = AAssetManager_openDir(_am, ""); - const char *file = AAssetDir_getNextFileName(dir); - - while (file) { - member_list.push_back(getMember(currentDir + Common::String(file))); - ++count; - file = AAssetDir_getNextFileName(dir); - } - AAssetDir_close(dir); - } - - _cachedMembers = Common::ArchiveMemberList(member_list); - _hasCached = true; - - return count; -} - -const Common::ArchiveMemberPtr AndroidAssetArchive::getMember(const Common::String &name) const { - return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(name, this)); -} - -Common::SeekableReadStream *AndroidAssetArchive::createReadStreamForMember(const Common::String &path) const { - if (!hasFile(path)) { - return nullptr; - } - return new AssetInputStream(_am, path); -} - -#endif +#define BACKEND_ANDROID3D +#include "../android/asset-archive.cpp" diff --git a/backends/platform/android3d/asset-archive.h b/backends/platform/android3d/asset-archive.h index 8ae55b22c99..a4122645457 100644 --- a/backends/platform/android3d/asset-archive.h +++ b/backends/platform/android3d/asset-archive.h @@ -1,54 +1 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#ifndef _ANDROID_ASSET_H_ -#define _ANDROID_ASSET_H_ - -#if defined(__ANDROID__) - -#include - -#include "common/str.h" -#include "common/stream.h" -#include "common/util.h" -#include "common/archive.h" - -#include - -class AndroidAssetArchive : public Common::Archive { -public: - AndroidAssetArchive(jobject am); - virtual ~AndroidAssetArchive(); - - virtual bool hasFile(const Common::String &name) const; - virtual int listMembers(Common::ArchiveMemberList &list) const; - virtual const Common::ArchiveMemberPtr getMember(const Common::String &name) const; - virtual Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const; - -private: - AAssetManager *_am; - mutable Common::ArchiveMemberList _cachedMembers; - mutable bool _hasCached; -}; - -#endif -#endif +#include "../android/asset-archive.h" diff --git a/backends/platform/android3d/jni-android.cpp b/backends/platform/android3d/jni-android.cpp index 257918c26c6..43e53908aa8 100644 --- a/backends/platform/android3d/jni-android.cpp +++ b/backends/platform/android3d/jni-android.cpp @@ -1,855 +1,2 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#if defined(__ANDROID__) - -// Allow use of stuff in and abort() -#define FORBIDDEN_SYMBOL_EXCEPTION_time_h -#define FORBIDDEN_SYMBOL_EXCEPTION_abort - -// Disable printf override in common/forbidden.h to avoid -// clashes with log.h from the Android SDK. -// That header file uses -// __attribute__ ((format(printf, 3, 4))) -// which gets messed up by our override mechanism; this could -// be avoided by either changing the Android SDK to use the equally -// legal and valid -// __attribute__ ((format(printf, 3, 4))) -// or by refining our printf override to use a varadic macro -// (which then wouldn't be portable, though). -// Anyway, for now we just disable the printf override globally -// for the Android port -#define FORBIDDEN_SYMBOL_EXCEPTION_printf - -#include "base/main.h" -#include "base/version.h" -#include "common/config-manager.h" -#include "common/error.h" -#include "common/textconsole.h" -#include "common/translation.h" -#include "common/encoding.h" -#include "engines/engine.h" - -#include "backends/platform/android3d/android.h" -#include "backends/platform/android3d/asset-archive.h" -#include "backends/platform/android3d/jni-android.h" - -__attribute__ ((visibility("default"))) -jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { - return JNI::onLoad(vm); -} - -JavaVM *JNI::_vm = 0; -jobject JNI::_jobj = 0; -jobject JNI::_jobj_audio_track = 0; -jobject JNI::_jobj_egl = 0; -jobject JNI::_jobj_egl_display = 0; -jobject JNI::_jobj_egl_surface = 0; - -Common::Archive *JNI::_asset_archive = 0; -OSystem_Android *JNI::_system = 0; - -bool JNI::pause = false; -sem_t JNI::pause_sem = { 0 }; - -int JNI::surface_changeid = 0; -int JNI::egl_surface_width = 0; -int JNI::egl_surface_height = 0; -bool JNI::_ready_for_events = 0; - -jmethodID JNI::_MID_getDPI = 0; -jmethodID JNI::_MID_displayMessageOnOSD = 0; -jmethodID JNI::_MID_openUrl = 0; -jmethodID JNI::_MID_hasTextInClipboard = 0; -jmethodID JNI::_MID_getTextFromClipboard = 0; -jmethodID JNI::_MID_setTextInClipboard = 0; -jmethodID JNI::_MID_isConnectionLimited = 0; -jmethodID JNI::_MID_setWindowCaption = 0; -jmethodID JNI::_MID_showVirtualKeyboard = 0; -jmethodID JNI::_MID_showKeyboardControl = 0; -jmethodID JNI::_MID_getSysArchives = 0; -jmethodID JNI::_MID_convertEncoding = 0; -jmethodID JNI::_MID_getAllStorageLocations = 0; -jmethodID JNI::_MID_initSurface = 0; -jmethodID JNI::_MID_deinitSurface = 0; -jmethodID JNI::_MID_createDirectoryWithSAF = 0; -jmethodID JNI::_MID_createFileWithSAF = 0; -jmethodID JNI::_MID_closeFileWithSAF = 0; - -jmethodID JNI::_MID_EGL10_eglSwapBuffers = 0; - -jmethodID JNI::_MID_AudioTrack_flush = 0; -jmethodID JNI::_MID_AudioTrack_pause = 0; -jmethodID JNI::_MID_AudioTrack_play = 0; -jmethodID JNI::_MID_AudioTrack_stop = 0; -jmethodID JNI::_MID_AudioTrack_write = 0; - -PauseToken JNI::_pauseToken; - -const JNINativeMethod JNI::_natives[] = { - { "create", "(Landroid/content/res/AssetManager;" - "Ljavax/microedition/khronos/egl/EGL10;" - "Ljavax/microedition/khronos/egl/EGLDisplay;" - "Landroid/media/AudioTrack;II)V", - (void *)JNI::create }, - { "destroy", "()V", - (void *)JNI::destroy }, - { "setSurface", "(II)V", - (void *)JNI::setSurface }, - { "main", "([Ljava/lang/String;)I", - (void *)JNI::main }, - { "pushEvent", "(IIIIIII)V", - (void *)JNI::pushEvent }, - { "setPause", "(Z)V", - (void *)JNI::setPause } -}; - -JNI::JNI() { -} - -JNI::~JNI() { -} - -jint JNI::onLoad(JavaVM *vm) { - _vm = vm; - - JNIEnv *env; - - if (_vm->GetEnv((void **)&env, JNI_VERSION_1_2)) - return JNI_ERR; - - jclass cls = env->FindClass("org/residualvm/residualvm/ResidualVM"); - if (cls == 0) - return JNI_ERR; - - if (env->RegisterNatives(cls, _natives, ARRAYSIZE(_natives)) < 0) - return JNI_ERR; - - return JNI_VERSION_1_2; -} - -JNIEnv *JNI::getEnv() { - JNIEnv *env = 0; - - jint res = _vm->GetEnv((void **)&env, JNI_VERSION_1_2); - - if (res != JNI_OK) { - LOGE("GetEnv() failed: %d", res); - abort(); - } - - return env; -} - -void JNI::attachThread() { - JNIEnv *env = 0; - - jint res = _vm->AttachCurrentThread(&env, 0); - - if (res != JNI_OK) { - LOGE("AttachCurrentThread() failed: %d", res); - abort(); - } -} - -void JNI::detachThread() { - jint res = _vm->DetachCurrentThread(); - - if (res != JNI_OK) { - LOGE("DetachCurrentThread() failed: %d", res); - abort(); - } -} - -void JNI::setReadyForEvents(bool ready) { - _ready_for_events = ready; -} - -void JNI::throwByName(JNIEnv *env, const char *name, const char *msg) { - jclass cls = env->FindClass(name); - - // if cls is 0, an exception has already been thrown - if (cls != 0) - env->ThrowNew(cls, msg); - - env->DeleteLocalRef(cls); -} - -void JNI::throwRuntimeException(JNIEnv *env, const char *msg) { - throwByName(env, "java/lang/RuntimeException", msg); -} - -// calls to the dark side - -void JNI::getDPI(float *values) { - values[0] = 0.0; - values[1] = 0.0; - - JNIEnv *env = JNI::getEnv(); - - jfloatArray array = env->NewFloatArray(2); - - env->CallVoidMethod(_jobj, _MID_getDPI, array); - - if (env->ExceptionCheck()) { - LOGE("Failed to get DPIs"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - } else { - jfloat *res = env->GetFloatArrayElements(array, 0); - - if (res) { - values[0] = res[0]; - values[1] = res[1]; - - env->ReleaseFloatArrayElements(array, res, 0); - } - } - - env->DeleteLocalRef(array); -} - -void JNI::displayMessageOnOSD(const Common::U32String &msg) { - // called from common/osd_message_queue, method: OSDMessageQueue::pollEvent() - JNIEnv *env = JNI::getEnv(); - - jstring java_msg = convertToJString(env, msg.encode(), "UTF-8"); - if (java_msg == nullptr) { - // Show a placeholder indicative of the translation error instead of silent failing - java_msg = env->NewStringUTF("?"); - LOGE("Failed to convert message to UTF-8 for OSD!"); - } - - env->CallVoidMethod(_jobj, _MID_displayMessageOnOSD, java_msg); - - if (env->ExceptionCheck()) { - LOGE("Failed to display OSD message"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - } - - env->DeleteLocalRef(java_msg); -} - -bool JNI::openUrl(const Common::String &url) { - bool success = true; - JNIEnv *env = JNI::getEnv(); - jstring javaUrl = env->NewStringUTF(url.c_str()); - - env->CallVoidMethod(_jobj, _MID_openUrl, javaUrl); - - if (env->ExceptionCheck()) { - LOGE("Failed to open URL"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - success = false; - } - - env->DeleteLocalRef(javaUrl); - return success; -} - -bool JNI::hasTextInClipboard() { - JNIEnv *env = JNI::getEnv(); - bool hasText = env->CallBooleanMethod(_jobj, _MID_hasTextInClipboard); - - if (env->ExceptionCheck()) { - LOGE("Failed to check the contents of the clipboard"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - hasText = true; - } - - return hasText; -} - -Common::U32String JNI::getTextFromClipboard() { - JNIEnv *env = JNI::getEnv(); - - jstring javaText = (jstring)env->CallObjectMethod(_jobj, _MID_getTextFromClipboard); - - if (env->ExceptionCheck()) { - LOGE("Failed to retrieve text from the clipboard"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - - return Common::U32String(); - } - - Common::String text = convertFromJString(env, javaText, "UTF-8"); - env->DeleteLocalRef(javaText); - - return text.decode(); -} - -bool JNI::setTextInClipboard(const Common::U32String &text) { - JNIEnv *env = JNI::getEnv(); - jstring javaText = convertToJString(env, text.encode(), "UTF-8"); - - bool success = env->CallBooleanMethod(_jobj, _MID_setTextInClipboard, javaText); - - if (env->ExceptionCheck()) { - LOGE("Failed to add text to the clipboard"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - success = false; - } - - env->DeleteLocalRef(javaText); - return success; -} - -bool JNI::isConnectionLimited() { - JNIEnv *env = JNI::getEnv(); - bool limited = env->CallBooleanMethod(_jobj, _MID_isConnectionLimited); - - if (env->ExceptionCheck()) { - LOGE("Failed to check whether connection's limited"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - limited = true; - } - - return limited; -} - -void JNI::setWindowCaption(const Common::String &caption) { - JNIEnv *env = JNI::getEnv(); - jstring java_caption = convertToJString(env, caption, "ISO-8859-1"); - - env->CallVoidMethod(_jobj, _MID_setWindowCaption, java_caption); - - if (env->ExceptionCheck()) { - LOGE("Failed to set window caption"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - } - - env->DeleteLocalRef(java_caption); -} - -void JNI::showVirtualKeyboard(bool enable) { - JNIEnv *env = JNI::getEnv(); - - env->CallVoidMethod(_jobj, _MID_showVirtualKeyboard, enable); - - if (env->ExceptionCheck()) { - LOGE("Error trying to show virtual keyboard"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - } -} - -void JNI::showKeyboardControl(bool enable) { - JNIEnv *env = JNI::getEnv(); - - env->CallVoidMethod(_jobj, _MID_showKeyboardControl, enable); - - if (env->ExceptionCheck()) { - LOGE("Error trying to show virtual keyboard control"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - } -} - -void JNI::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) { - JNIEnv *env = JNI::getEnv(); - - s.add("ASSET", _asset_archive, priority, false); - - jobjectArray array = - (jobjectArray)env->CallObjectMethod(_jobj, _MID_getSysArchives); - - if (env->ExceptionCheck()) { - LOGE("Error finding system archive path"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - - return; - } - - jsize size = env->GetArrayLength(array); - for (jsize i = 0; i < size; ++i) { - jstring path_obj = (jstring)env->GetObjectArrayElement(array, i); - const char *path = env->GetStringUTFChars(path_obj, 0); - - if (path != 0) { - s.addDirectory(path, path, priority); - env->ReleaseStringUTFChars(path_obj, path); - } - - env->DeleteLocalRef(path_obj); - } -} - -char *JNI::convertEncoding(const char *to, const char *from, const char *string, size_t length) { - JNIEnv *env = JNI::getEnv(); - - jstring javaTo = env->NewStringUTF(to); - jstring javaFrom = env->NewStringUTF(from); - jbyteArray javaString = env->NewByteArray(length); - env->SetByteArrayRegion(javaString, 0, length, reinterpret_cast(string)); - - jbyteArray javaOut = (jbyteArray)env->CallObjectMethod(_jobj, _MID_convertEncoding, javaTo, javaFrom, javaString); - - if (!javaOut || env->ExceptionCheck()) { - LOGE("Failed to convert text from %s to %s", from, to); - - env->ExceptionDescribe(); - env->ExceptionClear(); - - return nullptr; - } - - int outLength = env->GetArrayLength(javaOut); - char *buf = (char *)malloc(outLength + 1); - if (!buf) - return nullptr; - - env->GetByteArrayRegion(javaOut, 0, outLength, reinterpret_cast(buf)); - buf[outLength] = 0; - - return buf; -} - -bool JNI::initSurface() { - JNIEnv *env = JNI::getEnv(); - - jobject obj = env->CallObjectMethod(_jobj, _MID_initSurface); - - if (!obj || env->ExceptionCheck()) { - LOGE("initSurface failed"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - - return false; - } - - _jobj_egl_surface = env->NewGlobalRef(obj); - - return true; -} - -void JNI::deinitSurface() { - JNIEnv *env = JNI::getEnv(); - - env->CallVoidMethod(_jobj, _MID_deinitSurface); - - if (env->ExceptionCheck()) { - LOGE("deinitSurface failed"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - } - - env->DeleteGlobalRef(_jobj_egl_surface); - _jobj_egl_surface = 0; -} - -void JNI::setAudioPause() { - JNIEnv *env = JNI::getEnv(); - - env->CallVoidMethod(_jobj_audio_track, _MID_AudioTrack_flush); - - if (env->ExceptionCheck()) { - LOGE("Error flushing AudioTrack"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - } - - env->CallVoidMethod(_jobj_audio_track, _MID_AudioTrack_pause); - - if (env->ExceptionCheck()) { - LOGE("Error setting AudioTrack: pause"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - } -} - -void JNI::setAudioPlay() { - JNIEnv *env = JNI::getEnv(); - - env->CallVoidMethod(_jobj_audio_track, _MID_AudioTrack_play); - - if (env->ExceptionCheck()) { - LOGE("Error setting AudioTrack: play"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - } -} - -void JNI::setAudioStop() { - JNIEnv *env = JNI::getEnv(); - - env->CallVoidMethod(_jobj_audio_track, _MID_AudioTrack_stop); - - if (env->ExceptionCheck()) { - LOGE("Error setting AudioTrack: stop"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - } -} - -// natives for the dark side - -void JNI::create(JNIEnv *env, jobject self, jobject asset_manager, - jobject egl, jobject egl_display, - jobject at, jint audio_sample_rate, jint audio_buffer_size) { - LOGI("%s", gScummVMFullVersion); - - assert(!_system); - - pause = false; - // initial value of zero! - sem_init(&pause_sem, 0, 0); - - _asset_archive = new AndroidAssetArchive(asset_manager); - assert(_asset_archive); - - _system = new OSystem_Android(audio_sample_rate, audio_buffer_size); - assert(_system); - - // weak global ref to allow class to be unloaded - // ... except dalvik implements NewWeakGlobalRef only on froyo - //_jobj = env->NewWeakGlobalRef(self); - - _jobj = env->NewGlobalRef(self); - - jclass cls = env->GetObjectClass(_jobj); - -#define FIND_METHOD(prefix, name, signature) do { \ - _MID_ ## prefix ## name = env->GetMethodID(cls, #name, signature); \ - if (_MID_ ## prefix ## name == 0) \ - return; \ - } while (0) - - FIND_METHOD(, setWindowCaption, "(Ljava/lang/String;)V"); - FIND_METHOD(, getDPI, "([F)V"); - FIND_METHOD(, displayMessageOnOSD, "(Ljava/lang/String;)V"); - FIND_METHOD(, openUrl, "(Ljava/lang/String;)V"); - FIND_METHOD(, hasTextInClipboard, "()Z"); - FIND_METHOD(, getTextFromClipboard, "()Ljava/lang/String;"); - FIND_METHOD(, setTextInClipboard, "(Ljava/lang/String;)Z"); - FIND_METHOD(, isConnectionLimited, "()Z"); - FIND_METHOD(, showVirtualKeyboard, "(Z)V"); - FIND_METHOD(, showKeyboardControl, "(Z)V"); - FIND_METHOD(, getSysArchives, "()[Ljava/lang/String;"); - FIND_METHOD(, getAllStorageLocations, "()[Ljava/lang/String;"); - FIND_METHOD(, convertEncoding, "(Ljava/lang/String;Ljava/lang/String;[B)[B"); - FIND_METHOD(, initSurface, "()Ljavax/microedition/khronos/egl/EGLSurface;"); - FIND_METHOD(, deinitSurface, "()V"); - FIND_METHOD(, createDirectoryWithSAF, "(Ljava/lang/String;)Z"); - FIND_METHOD(, createFileWithSAF, "(Ljava/lang/String;)Ljava/lang/String;"); - FIND_METHOD(, closeFileWithSAF, "(Ljava/lang/String;)V"); - - _jobj_egl = env->NewGlobalRef(egl); - _jobj_egl_display = env->NewGlobalRef(egl_display); - - cls = env->GetObjectClass(_jobj_egl); - - FIND_METHOD(EGL10_, eglSwapBuffers, - "(Ljavax/microedition/khronos/egl/EGLDisplay;" - "Ljavax/microedition/khronos/egl/EGLSurface;)Z"); - - _jobj_audio_track = env->NewGlobalRef(at); - - cls = env->GetObjectClass(_jobj_audio_track); - - FIND_METHOD(AudioTrack_, flush, "()V"); - FIND_METHOD(AudioTrack_, pause, "()V"); - FIND_METHOD(AudioTrack_, play, "()V"); - FIND_METHOD(AudioTrack_, stop, "()V"); - FIND_METHOD(AudioTrack_, write, "([BII)I"); - -#undef FIND_METHOD - - g_system = _system; -} - -void JNI::destroy(JNIEnv *env, jobject self) { - delete _asset_archive; - _asset_archive = 0; - - // _system is a pointer of OSystem_Android <--- ModularBackend <--- BaseBacked <--- Common::OSystem - // It's better to call destroy() rather than just delete here - // to avoid mutex issues if a Common::String is used after this point - _system->destroy(); - - g_system = 0; - _system = 0; - - sem_destroy(&pause_sem); - - // see above - //JNI::getEnv()->DeleteWeakGlobalRef(_jobj); - - JNI::getEnv()->DeleteGlobalRef(_jobj_egl_display); - JNI::getEnv()->DeleteGlobalRef(_jobj_egl); - JNI::getEnv()->DeleteGlobalRef(_jobj_audio_track); - JNI::getEnv()->DeleteGlobalRef(_jobj); -} - -void JNI::setSurface(JNIEnv *env, jobject self, jint width, jint height) { - egl_surface_width = width; - egl_surface_height = height; - surface_changeid++; -} - -jint JNI::main(JNIEnv *env, jobject self, jobjectArray args) { - assert(_system); - - const int MAX_NARGS = 32; - int res = -1; - - int argc = env->GetArrayLength(args); - if (argc > MAX_NARGS) { - throwByName(env, "java/lang/IllegalArgumentException", - "too many arguments"); - return 0; - } - - char *argv[MAX_NARGS]; - - // note use in cleanup loop below - int nargs; - - for (nargs = 0; nargs < argc; ++nargs) { - jstring arg = (jstring)env->GetObjectArrayElement(args, nargs); - - if (arg == 0) { - argv[nargs] = 0; - } else { - const char *cstr = env->GetStringUTFChars(arg, 0); - - argv[nargs] = const_cast(cstr); - - // exception already thrown? - if (cstr == 0) - goto cleanup; - } - - env->DeleteLocalRef(arg); - } - - LOGI("Entering scummvm_main with %d args", argc); - - res = scummvm_main(argc, argv); - - LOGI("scummvm_main exited with code %d", res); - - _system->quit(); - -cleanup: - nargs--; - - for (int i = 0; i < nargs; ++i) { - if (argv[i] == 0) - continue; - - jstring arg = (jstring)env->GetObjectArrayElement(args, nargs); - - // Exception already thrown? - if (arg == 0) - return res; - - env->ReleaseStringUTFChars(arg, argv[i]); - env->DeleteLocalRef(arg); - } - - return res; -} - -void JNI::pushEvent(JNIEnv *env, jobject self, int type, int arg1, int arg2, - int arg3, int arg4, int arg5, int arg6) { - // drop events until we're ready and after we quit - if (!_ready_for_events) { - LOGW("dropping event"); - return; - } - - assert(_system); - - _system->pushEvent(type, arg1, arg2, arg3, arg4, arg5, arg6); -} - -void JNI::setPause(JNIEnv *env, jobject self, jboolean value) { - if (!_system) - return; - - if (g_engine) { - LOGD("pauseEngine: %d", value); - - if (value) - JNI::_pauseToken = g_engine->pauseEngine(); - else - JNI::_pauseToken.clear(); - - if (value && - g_engine->hasFeature(Engine::kSupportsSavingDuringRuntime) && - g_engine->canSaveGameStateCurrently()) - g_engine->saveGameState(0, "Android parachute"); - } - - pause = value; - - if (!pause) { - // wake up all threads - for (uint i = 0; i < 3; ++i) - sem_post(&pause_sem); - } -} - -jstring JNI::convertToJString(JNIEnv *env, const Common::String &str, const Common::String &from) { - Common::Encoding converter("UTF-8", from.c_str()); - char *utf8Str = converter.convert(str.c_str(), converter.stringLength(str.c_str(), from)); - if (utf8Str == nullptr) - return nullptr; - - jstring jstr = env->NewStringUTF(utf8Str); - free(utf8Str); - - return jstr; -} - -Common::String JNI::convertFromJString(JNIEnv *env, const jstring &jstr, const Common::String &to) { - const char *utf8Str = env->GetStringUTFChars(jstr, 0); - if (!utf8Str) - return Common::String(); - - Common::Encoding converter(to.c_str(), "UTF-8"); - char *asciiStr = converter.convert(utf8Str, env->GetStringUTFLength(jstr)); - env->ReleaseStringUTFChars(jstr, utf8Str); - - Common::String str(asciiStr); - free(asciiStr); - - return str; -} - -Common::Array JNI::getAllStorageLocations() { - Common::Array *res = new Common::Array(); - - JNIEnv *env = JNI::getEnv(); - - jobjectArray array = - (jobjectArray)env->CallObjectMethod(_jobj, _MID_getAllStorageLocations); - - if (env->ExceptionCheck()) { - LOGE("Error finding system archive path"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - - return *res; - } - - jsize size = env->GetArrayLength(array); - for (jsize i = 0; i < size; ++i) { - jstring path_obj = (jstring)env->GetObjectArrayElement(array, i); - const char *path = env->GetStringUTFChars(path_obj, 0); - - if (path != 0) { - res->push_back(path); - env->ReleaseStringUTFChars(path_obj, path); - } - - env->DeleteLocalRef(path_obj); - } - - return *res; -} - -bool JNI::createDirectoryWithSAF(const Common::String &dirPath) { - JNIEnv *env = JNI::getEnv(); - jstring javaDirPath = env->NewStringUTF(dirPath.c_str()); - - bool created = env->CallBooleanMethod(_jobj, _MID_createDirectoryWithSAF, javaDirPath); - - if (env->ExceptionCheck()) { - LOGE("JNI - Failed to create directory with SAF enhanced method"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - created = false; - } - - return created; - -} - -Common::String JNI::createFileWithSAF(const Common::String &filePath) { - JNIEnv *env = JNI::getEnv(); - jstring javaFilePath = env->NewStringUTF(filePath.c_str()); - - jstring hackyFilenameJSTR = (jstring)env->CallObjectMethod(_jobj, _MID_createFileWithSAF, javaFilePath); - - - if (env->ExceptionCheck()) { - LOGE("JNI - Failed to create file with SAF enhanced method"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - hackyFilenameJSTR = env->NewStringUTF(""); - } - - Common::String hackyFilenameStr = convertFromJString(env, hackyFilenameJSTR, "UTF-8"); - - //LOGD("JNI - _MID_createFileWithSAF returned %s", hackyFilenameStr.c_str()); - env->DeleteLocalRef(hackyFilenameJSTR); - - return hackyFilenameStr; - -} - -void JNI::closeFileWithSAF(const Common::String &hackyFilename) { - JNIEnv *env = JNI::getEnv(); - jstring javaHackyFilename = env->NewStringUTF(hackyFilename.c_str()); - - env->CallVoidMethod(_jobj, _MID_closeFileWithSAF, javaHackyFilename); - - if (env->ExceptionCheck()) { - LOGE("JNI - Failed to close file with SAF enhanced method"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - } - -} - - -#endif +#define BACKEND_ANDROID3D +#include "../android/jni-android.cpp" diff --git a/backends/platform/android3d/jni-android.h b/backends/platform/android3d/jni-android.h index 393c78ad6c4..7db23636139 100644 --- a/backends/platform/android3d/jni-android.h +++ b/backends/platform/android3d/jni-android.h @@ -1,175 +1 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#ifndef _ANDROID_JNI_H_ -#define _ANDROID_JNI_H_ - -#if defined(__ANDROID__) - -#include -#include - -#include "common/fs.h" -#include "common/archive.h" -#include "common/array.h" -#include "common/ustr.h" -#include "engines/engine.h" - -class OSystem_Android; - -class JNI { -private: - JNI(); - virtual ~JNI(); - -public: - static bool pause; - static sem_t pause_sem; - - static int surface_changeid; - static int egl_surface_width; - static int egl_surface_height; - - static jint onLoad(JavaVM *vm); - - static JNIEnv *getEnv(); - - static void attachThread(); - static void detachThread(); - - static void setReadyForEvents(bool ready); - - static void setWindowCaption(const Common::String &caption); - static void getDPI(float *values); - static void displayMessageOnOSD(const Common::U32String &msg); - static bool openUrl(const Common::String &url); - static bool hasTextInClipboard(); - static Common::U32String getTextFromClipboard(); - static bool setTextInClipboard(const Common::U32String &text); - static bool isConnectionLimited(); - static void showVirtualKeyboard(bool enable); - static void showKeyboardControl(bool enable); - static void addSysArchivesToSearchSet(Common::SearchSet &s, int priority); - static char *convertEncoding(const char *to, const char *from, const char *string, size_t length); - - static inline bool haveSurface(); - static inline bool swapBuffers(); - static bool initSurface(); - static void deinitSurface(); - - static void setAudioPause(); - static void setAudioPlay(); - static void setAudioStop(); - - static inline int writeAudio(JNIEnv *env, jbyteArray &data, int offset, - int size); - - static Common::Array getAllStorageLocations(); - - static bool createDirectoryWithSAF(const Common::String &dirPath); - static Common::String createFileWithSAF(const Common::String &filePath); - static void closeFileWithSAF(const Common::String &hackyFilename); - -private: - static JavaVM *_vm; - // back pointer to (java) peer instance - static jobject _jobj; - static jobject _jobj_audio_track; - static jobject _jobj_egl; - static jobject _jobj_egl_display; - static jobject _jobj_egl_surface; - - static Common::Archive *_asset_archive; - static OSystem_Android *_system; - - static bool _ready_for_events; - - static jmethodID _MID_getDPI; - static jmethodID _MID_displayMessageOnOSD; - static jmethodID _MID_openUrl; - static jmethodID _MID_hasTextInClipboard; - static jmethodID _MID_getTextFromClipboard; - static jmethodID _MID_setTextInClipboard; - static jmethodID _MID_isConnectionLimited; - static jmethodID _MID_setWindowCaption; - static jmethodID _MID_showVirtualKeyboard; - static jmethodID _MID_showKeyboardControl; - static jmethodID _MID_getSysArchives; - static jmethodID _MID_convertEncoding; - static jmethodID _MID_getAllStorageLocations; - static jmethodID _MID_initSurface; - static jmethodID _MID_deinitSurface; - static jmethodID _MID_createDirectoryWithSAF; - static jmethodID _MID_createFileWithSAF; - static jmethodID _MID_closeFileWithSAF; - - static jmethodID _MID_EGL10_eglSwapBuffers; - - static jmethodID _MID_AudioTrack_flush; - static jmethodID _MID_AudioTrack_pause; - static jmethodID _MID_AudioTrack_play; - static jmethodID _MID_AudioTrack_stop; - static jmethodID _MID_AudioTrack_write; - - static const JNINativeMethod _natives[]; - - static void throwByName(JNIEnv *env, const char *name, const char *msg); - static void throwRuntimeException(JNIEnv *env, const char *msg); - - // natives for the dark side - static void create(JNIEnv *env, jobject self, jobject asset_manager, - jobject egl, jobject egl_display, - jobject at, jint audio_sample_rate, - jint audio_buffer_size); - static void destroy(JNIEnv *env, jobject self); - - static void setSurface(JNIEnv *env, jobject self, jint width, jint height); - static jint main(JNIEnv *env, jobject self, jobjectArray args); - - static void pushEvent(JNIEnv *env, jobject self, int type, int arg1, - int arg2, int arg3, int arg4, int arg5, int arg6); - static void setPause(JNIEnv *env, jobject self, jboolean value); - - static jstring convertToJString(JNIEnv *env, const Common::String &str, const Common::String &from); - static Common::String convertFromJString(JNIEnv *env, const jstring &jstr, const Common::String &to); - - static PauseToken _pauseToken; -}; - -inline bool JNI::haveSurface() { - return _jobj_egl_surface != 0; -} - -inline bool JNI::swapBuffers() { - JNIEnv *env = JNI::getEnv(); - - return env->CallBooleanMethod(_jobj_egl, _MID_EGL10_eglSwapBuffers, - _jobj_egl_display, _jobj_egl_surface); -} - -inline int JNI::writeAudio(JNIEnv *env, jbyteArray &data, int offset, int size) { - return env->CallIntMethod(_jobj_audio_track, _MID_AudioTrack_write, data, - offset, size); -} - -#endif -#endif +#include "../android/jni-android.h" diff --git a/backends/platform/android3d/portdefs.h b/backends/platform/android3d/portdefs.h index dda6a29c2d6..7a1402317f7 100644 --- a/backends/platform/android3d/portdefs.h +++ b/backends/platform/android3d/portdefs.h @@ -1,48 +1,2 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ +#include "../android/portdefs.h" -#ifndef _PORTDEFS_H_ -#define _PORTDEFS_H_ - -#include -#include -#include -#include -#include -#include -#include - -#define _USE_MATH_DEFINES -#include - -// This is defined in snprintf.c -#ifdef __cplusplus -extern "C" { -#endif -int rpl_vsnprintf(char *text, size_t maxlen, const char *fmt, va_list ap); -#ifdef __cplusplus -} -#endif - -#define vsnprintf rpl_vsnprintf - -#endif // _PORTDEFS_H_