Make android callback thread safe

This commit is contained in:
Benau 2019-05-27 12:17:08 +08:00
parent febad27342
commit a96071f9d3
4 changed files with 53 additions and 8 deletions

View File

@ -9,6 +9,7 @@
#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_
#include <assert.h>
#include <atomic>
#include <vector>
#include "os.h"
#include "CContextEGL.h"
@ -43,7 +44,7 @@ ANDROID_SAVE_CHARS_CALLBACK(ANDROID_PACKAGE_CALLBACK_NAME)
// Call when android keyboard is opened or close, and save its height for
// moving screen
int g_keyboard_height = 0;
std::atomic<int> g_keyboard_height(0);
#define MAKE_ANDROID_SAVE_KBD_HEIGHT_CALLBACK(x) JNIEXPORT void JNICALL Java_ ## x##_SuperTuxKartActivity_saveKeyboardHeight(JNIEnv* env, jobject this_obj, jint height)
#define ANDROID_SAVE_KBD_HEIGHT_CALLBACK(PKG_NAME) MAKE_ANDROID_SAVE_KBD_HEIGHT_CALLBACK(PKG_NAME)
@ -51,7 +52,7 @@ int g_keyboard_height = 0;
extern "C"
ANDROID_SAVE_KBD_HEIGHT_CALLBACK(ANDROID_PACKAGE_CALLBACK_NAME)
{
g_keyboard_height = (int)height;
g_keyboard_height.store((int)height);
}
namespace irr
@ -227,8 +228,9 @@ void CIrrDeviceAndroid::printConfig()
u32 CIrrDeviceAndroid::getOnScreenKeyboardHeight() const
{
if (g_keyboard_height > 0)
return g_keyboard_height;
int height = g_keyboard_height.load();
if (height > 0)
return height;
return 0;
}

View File

@ -685,9 +685,11 @@ namespace GUIEngine
#include "states_screens/race_gui_base.hpp"
#include "utils/debug.hpp"
#include <algorithm>
#include <iostream>
#include <assert.h>
#include <irrlicht.h>
#include <mutex>
using namespace irr::gui;
using namespace irr::video;
@ -716,6 +718,10 @@ namespace GUIEngine
int large_font_height;
int small_font_height;
int title_font_height;
#ifdef ANDROID
std::mutex m_gui_functions_mutex;
std::vector<std::function<void()> > m_gui_functions;
#endif
}
using namespace Private;
@ -1144,6 +1150,15 @@ namespace GUIEngine
assert(g_skin->getReferenceCount() == 1);
} // reloadSkin
// -----------------------------------------------------------------------
void addGUIFunctionBeforeRendering(std::function<void()> func)
{
#ifdef ANDROID
std::lock_guard<std::mutex> lock(m_gui_functions_mutex);
m_gui_functions.push_back(func);
#endif
} // addGUIFunctionBeforeRendering
// -----------------------------------------------------------------------
/** \brief called on every frame to trigger the rendering of the GUI.
* \param elapsed_time Time since last rendering calls (in seconds).
@ -1158,6 +1173,21 @@ namespace GUIEngine
// Not yet initialized, or already cleaned up
if (g_skin == NULL) return;
#ifdef ANDROID
// Run all GUI functions first (if any)
std::unique_lock<std::mutex> ul(m_gui_functions_mutex);
if (!m_gui_functions.empty())
{
std::vector<std::function<void()> > functions;
std::swap(functions, m_gui_functions);
ul.unlock();
for (auto& f : functions)
f();
}
else
ul.unlock();
#endif
// ---- menu drawing
// draw background image and sections

View File

@ -34,6 +34,7 @@ namespace irr
namespace video { class IVideoDriver; class ITexture; }
}
#include <functional>
#include <string>
#include "utils/constants.hpp"
@ -248,6 +249,10 @@ namespace GUIEngine
*/
void reloadSkin();
/**
* \brief Add gui-related function before rendering GUI (from other thread)
*/
void addGUIFunctionBeforeRendering(std::function<void()> func);
}
#endif

View File

@ -246,8 +246,7 @@ EventPropagation TextBoxWidget::leftPressed (const int playerID)
extern "C"
ANDROID_EDITTEXT_CALLBACK(ANDROID_PACKAGE_CALLBACK_NAME)
{
TextBoxWidget* tb = dynamic_cast<TextBoxWidget*>(getFocusForPlayer(0));
if (!tb || (int)widget_id != tb->getID() || text == NULL)
if (text == NULL)
return;
const char* utf8_text = env->GetStringUTFChars(text, NULL);
@ -262,8 +261,17 @@ ANDROID_EDITTEXT_CALLBACK(ANDROID_PACKAGE_CALLBACK_NAME)
utf32line.push_back(0);
core::stringw to_editbox(&utf32line[0]);
tb->getIrrlichtElement<MyCGUIEditBox>()->fromAndroidEditText(
to_editbox, start, end, composing_start, composing_end);
env->ReleaseStringUTFChars(text, utf8_text);
GUIEngine::addGUIFunctionBeforeRendering([widget_id, to_editbox, start,
end, composing_start, composing_end]()
{
TextBoxWidget* tb =
dynamic_cast<TextBoxWidget*>(getFocusForPlayer(0));
if (!tb || (int)widget_id != tb->getID())
return;
tb->getIrrlichtElement<MyCGUIEditBox>()->fromAndroidEditText(
to_editbox, start, end, composing_start, composing_end);
});
}
#endif