Skip to content
This repository was archived by the owner on Aug 31, 2021. It is now read-only.

Commit ff9b10c

Browse files
committed
[[ AndroidButton ]] Temporary fix to thread affinity and android button
This patch implemented a temporary way of expressing thread affinity when binding to java method on android. If a method of an Android Java object requires that it be run on the UI thread, then the binding string should use 'javaui' and not 'java'. Any handlers bound with 'javaui' will ensure that the engine is running on the Android UI thread before calling them, and return to the original thread thereafter. Furthermore, all methods invoked using interface proxy callbacks (via the LCBInvocation proxy) will ensure they are called on the engine's script thread. The button example has been modified to use 'javaui' in appropriate places, and the label property has been renamed to 'label'.
1 parent 70911f2 commit ff9b10c

File tree

8 files changed

+126
-26
lines changed

8 files changed

+126
-26
lines changed

engine/src/mblandroiddc.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ static void co_leave_engine(void);
162162
static void co_yield_to_engine(void);
163163
static void co_yield_to_android(void);
164164
static bool co_yield_to_android_and_wait(double sleep, bool wake_on_event);
165-
static void co_yield_to_android_and_call(co_yield_callback_t callback, void *context);
165+
void co_yield_to_android_and_call(co_yield_callback_t callback, void *context);
166166

167167
static void revandroid_scheduleWakeUp(JNIEnv *env, jobject object, int32_t timeout, bool breakable);
168168
static void revandroid_invalidate(JNIEnv *env, jobject object, int32_t left, int32_t top, int32_t right, int32_t bottom);
@@ -1451,7 +1451,7 @@ static void co_yield_to_engine(void)
14511451
}
14521452
}
14531453

1454-
static void co_yield_to_engine_and_call(co_yield_callback_t callback, void *context)
1454+
void co_yield_to_engine_and_call(co_yield_callback_t callback, void *context)
14551455
{
14561456
void *t_stack;
14571457
s_yield_callback = callback;
@@ -1491,7 +1491,7 @@ static bool co_yield_to_android_and_wait(double p_sleep, bool p_wake_on_event)
14911491
return s_schedule_wakeup_was_broken;
14921492
}
14931493

1494-
static void co_yield_to_android_and_call(co_yield_callback_t callback, void *context)
1494+
void co_yield_to_android_and_call(co_yield_callback_t callback, void *context)
14951495
{
14961496
void *t_stack;
14971497
s_schedule_wakeup = false;
@@ -1951,6 +1951,11 @@ void *MCAndroidGetEngine(void)
19511951
return s_android_view;
19521952
}
19531953

1954+
bool MCAndroidIsOnSystemThread(void)
1955+
{
1956+
return s_android_ui_thread.IsCurrent();
1957+
}
1958+
19541959
////////////////////////////////////////////////////////////////////////////////
19551960

19561961
extern "C" JNIEXPORT void JNICALL Java_com_runrev_android_Engine_doCreate(JNIEnv *env, jobject object, jobject activity, jobject container, jobject view) __attribute__((visibility("default")));

engine/src/mblandroidlcb.cpp

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,41 @@
3535

3636
extern void MCJavaPrivateDoNativeListenerCallback(jlong p_handler, jstring p_method_name, jobjectArray p_args);
3737

38+
#ifdef TARGET_SUBPLATFORM_ANDROID
39+
struct remote_call_t
40+
{
41+
jlong p_handler;
42+
jstring p_method_name;
43+
jobjectArray p_args;
44+
};
45+
46+
static void remote_call_func(void *p_context)
47+
{
48+
auto ctxt = static_cast<remote_call_t *>(p_context);
49+
MCJavaPrivateDoNativeListenerCallback(ctxt->p_handler, ctxt->p_method_name, ctxt->p_args);
50+
}
51+
#endif
52+
3853
extern "C" JNIEXPORT void JNICALL Java_com_runrev_android_LCBInvocationHandler_doNativeListenerCallback(JNIEnv *env, jobject object, jlong handler, jstring p_method, jobjectArray p_args) __attribute__((visibility("default")));
3954

4055
JNIEXPORT void JNICALL Java_com_runrev_android_LCBInvocationHandler_doNativeListenerCallback(JNIEnv *env, jobject object, jlong p_handler, jstring p_method_name, jobjectArray p_args)
4156
{
42-
MCJavaPrivateDoNativeListenerCallback(p_handler, p_method_name, p_args);
57+
#ifdef TARGET_SUBPLATFORM_ANDROID
58+
extern bool MCAndroidIsOnSystemThread(void);
59+
if (MCAndroidIsOnSystemThread())
60+
{
61+
typedef void (*co_yield_callback_t)(void *);
62+
extern void co_yield_to_engine_and_call(co_yield_callback_t callback, void *context);
63+
remote_call_t t_context = {p_handler, p_method_name, p_args};
64+
co_yield_to_engine_and_call(remote_call_func, &t_context);
65+
}
66+
else
67+
{
68+
#endif
69+
MCJavaPrivateDoNativeListenerCallback(p_handler, p_method_name, p_args);
70+
#ifdef TARGET_SUBPLATFORM_ANDROID
71+
}
72+
#endif
4373

4474
// At the moment we have no way of dealing with any errors thrown in
4575
// the course of handling or attempting to handle the native listener

extensions/widgets/androidbutton/androidbutton.lcb

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,23 +48,23 @@ metadata title is "Android Native Button"
4848

4949
/**
5050
Syntax:
51-
set the buttonLabel of <widget> to <pLabel>
52-
get the buttonLabel of <widget>
51+
set the label of <widget> to <pLabel>
52+
get the label of <widget>
5353

5454
Summary: The label displayed by the button.
5555

5656
Value (string): The string to use as the button label
5757

5858
Example:
59-
set the buttonLabel of widget "Android Button" to "Click me!"
59+
set the label of widget "Android Button" to "Click me!"
6060

6161
Description:
62-
The <buttonLabel> property is the label displayed by the button.
62+
The <label> property is the label displayed by the button.
6363
*/
6464

65-
property buttonLabel get mLabel set SetLabel
66-
metadata buttonLabel.editor is "com.livecode.pi.string"
67-
metadata buttonLabel.default is ""
65+
property label get mLabel set SetLabel
66+
metadata label.editor is "com.livecode.pi.string"
67+
metadata label.default is ""
6868

6969
/**
7070
Syntax:
@@ -93,19 +93,19 @@ foreign handler _JNI_GetAndroidEngine() returns JObject binds to "java:com.runre
9393
foreign handler _JNI_GetEngineContext(in pEngine as JObject) returns JObject binds to "java:android.view.View>getContext()Landroid/content/Context;"
9494

9595
// Handlers for creating and attaching view
96-
foreign handler _JNI_CreateButton(in pContext as JObject) returns JObject binds to "java:android.widget.Button>new(Landroid/content/Context;)"
97-
foreign handler _JNI_AddButtonView(in pParentView as JObject, in pChildView as JObject) returns nothing binds to "java:android.view.ViewGroup>addView(Landroid/view/View;)V"
96+
foreign handler _JNI_CreateButton(in pContext as JObject) returns JObject binds to "javaui:android.widget.Button>new(Landroid/content/Context;)"
97+
foreign handler _JNI_AddButtonView(in pParentView as JObject, in pChildView as JObject) returns nothing binds to "javaui:android.view.ViewGroup>addView(Landroid/view/View;)V"
9898

9999
// Handlers for adding click listener
100100
handler type ClickCallback(in pView as JObject)
101101
foreign handler _JNI_OnClickListener(in pHandler as ClickCallback) returns JObject binds to "java:android.view.View$OnClickListener>interface()"
102-
foreign handler _JNI_SetOnClickListener(in pButton as JObject, in pListener as JObject) returns nothing binds to "java:android.view.View>setOnClickListener(Landroid/view/View$OnClickListener;)V"
102+
foreign handler _JNI_SetOnClickListener(in pButton as JObject, in pListener as JObject) returns nothing binds to "javaui:android.view.View>setOnClickListener(Landroid/view/View$OnClickListener;)V"
103103

104104
// Property setters
105-
foreign handler _JNI_SetTextViewText(in pView as JObject, in pValue as JString) returns nothing binds to "java:android.widget.TextView>setText(Ljava/lang/CharSequence;)V"
106-
foreign handler _JNI_SetTextViewTextColor(in pView as JObject, in pValue as JInt) returns nothing binds to "java:android.widget.TextView>setTextColor(I)V"
105+
foreign handler _JNI_SetTextViewText(in pView as JObject, in pValue as JString) returns nothing binds to "javaui:android.widget.TextView>setText(Ljava/lang/CharSequence;)V"
106+
foreign handler _JNI_SetTextViewTextColor(in pView as JObject, in pValue as JInt) returns nothing binds to "javaui:android.widget.TextView>setTextColor(I)V"
107107
foreign handler _JNI_GetColorFromARGB(in pA as JInt, in pR as JInt, in pG as JInt, in pB as JInt) returns JInt binds to "java:android.graphics.Color>argb(IIII)I!static"
108-
foreign handler _JNI_SetTextViewEnabled(in pView as JObject, in pValue as JBoolean) returns nothing binds to "java:android.view.View>setEnabled(Z)V"
108+
foreign handler _JNI_SetTextViewEnabled(in pView as JObject, in pValue as JBoolean) returns nothing binds to "javaui:android.view.View>setEnabled(Z)V"
109109

110110
private variable mLabel as String
111111
private variable mColor as String

libfoundation/src/foundation-java-private.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1400,6 +1400,16 @@ bool MCJavaCreateInterfaceProxy(MCNameRef p_class_name, MCTypeInfoRef p_signatur
14001400
return true;
14011401
}
14021402

1403+
bool MCJavaPrivateCallJNIMethodOnEnv(void *p_env, MCNameRef p_class_name, void *p_method_id, int p_call_type, MCTypeInfoRef p_signature, void *r_return, void **p_args, uindex_t p_arg_count)
1404+
{
1405+
JNIEnv *t_old_env;
1406+
t_old_env = s_env;
1407+
s_env = (JNIEnv *)p_env;
1408+
bool t_success = MCJavaPrivateCallJNIMethod(p_class_name, p_method_id, p_call_type, p_signature, r_return, p_args, p_arg_count);
1409+
s_env = t_old_env;
1410+
return t_success;
1411+
}
1412+
14031413
bool MCJavaPrivateCallJNIMethod(MCNameRef p_class_name, void *p_method_id, int p_call_type, MCTypeInfoRef p_signature, void *r_return, void **p_args, uindex_t p_arg_count)
14041414
{
14051415
if (p_method_id == nullptr)

libfoundation/src/foundation-java-private.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ typedef struct __MCJavaObject *MCJavaObjectRef;
5454

5555

5656
bool MCJavaPrivateCallJNIMethod(MCNameRef p_class_name, void *p_method_id, int p_call_type, MCTypeInfoRef p_signature, void *r_return, void **p_args, uindex_t p_arg_count);
57+
bool MCJavaPrivateCallJNIMethodOnEnv(void *p_env, MCNameRef p_class_name, void *p_method_id, int p_call_type, MCTypeInfoRef p_signature, void *r_return, void **p_args, uindex_t p_arg_count);
5758
bool MCJavaPrivateObjectDescribe(MCValueRef p_value, MCStringRef &r_desc);
5859
bool MCJavaPrivateConvertJStringToStringRef(MCJavaObjectRef p_object, MCStringRef &r_string);
5960
bool MCJavaPrivateConvertStringRefToJString(MCStringRef p_string, MCJavaObjectRef &r_object);

libscript/src/script-execute.cpp

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,34 @@ static void __MCScriptDropValueRef(void *p_value)
3636
MCValueRelease(*(MCValueRef *)p_value);
3737
}
3838

39+
#ifdef TARGET_SUBPLATFORM_ANDROID
40+
struct remote_call_t
41+
{
42+
MCScriptForeignHandlerDefinition *p_handler;
43+
MCTypeInfoRef p_handler_signature;
44+
void *p_result_slot_ptr;
45+
void **m_argument_values;
46+
uindex_t m_argument_count;
47+
};
48+
49+
static void remote_call_func(void *p_context)
50+
{
51+
extern void *MCAndroidGetSystemJavaEnv();
52+
auto ctxt = static_cast<remote_call_t *>(p_context);
53+
54+
extern bool MCJavaPrivateCallJNIMethodOnEnv(void *p_env, MCNameRef p_class, void *p_method_id, int p_call_type, MCTypeInfoRef p_signature, void *r_return, void **p_args, uindex_t p_arg_count);
55+
56+
MCJavaPrivateCallJNIMethodOnEnv(MCAndroidGetSystemJavaEnv(),
57+
ctxt -> p_handler -> java . class_name,
58+
ctxt -> p_handler -> java . method_id,
59+
ctxt -> p_handler -> java . call_type,
60+
ctxt -> p_handler_signature,
61+
ctxt -> p_result_slot_ptr,
62+
ctxt -> m_argument_values,
63+
ctxt -> m_argument_count);
64+
}
65+
#endif
66+
3967
class MCScriptForeignInvocation
4068
{
4169
public:
@@ -141,13 +169,35 @@ class MCScriptForeignInvocation
141169
{
142170
if (p_handler->is_java)
143171
{
144-
MCJavaCallJNIMethod(p_handler -> java . class_name,
145-
p_handler -> java . method_id,
146-
p_handler -> java . call_type,
147-
p_handler_signature,
148-
p_result_slot_ptr,
149-
m_argument_values,
150-
m_argument_count);
172+
#ifdef TARGET_SUBPLATFORM_ANDROID
173+
extern bool MCAndroidIsOnSystemThread();
174+
if (!p_handler->is_ui_bound || MCAndroidIsOnSystemThread())
175+
#endif
176+
{
177+
MCJavaCallJNIMethod(p_handler -> java . class_name,
178+
p_handler -> java . method_id,
179+
p_handler -> java . call_type,
180+
p_handler_signature,
181+
p_result_slot_ptr,
182+
m_argument_values,
183+
m_argument_count);
184+
}
185+
#ifdef TARGET_SUBPLATFORM_ANDROID
186+
else
187+
{
188+
typedef void (*co_yield_callback_t)(void *);
189+
extern void co_yield_to_android_and_call(co_yield_callback_t callback, void *context);
190+
remote_call_t t_context =
191+
{
192+
p_handler,
193+
p_handler_signature,
194+
p_result_slot_ptr,
195+
m_argument_values,
196+
m_argument_count
197+
};
198+
co_yield_to_android_and_call(remote_call_func, &t_context);
199+
}
200+
#endif
151201
}
152202
else if (p_handler->is_builtin)
153203
{
@@ -164,7 +214,7 @@ class MCScriptForeignInvocation
164214

165215
return true;
166216
}
167-
217+
168218
// Take the contents of a slot - this stops the invocation
169219
// cleaning up the taken slot.
170220
void *TakeArgument(uindex_t p_index)

libscript/src/script-instance.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -857,8 +857,11 @@ __MCScriptResolveForeignFunctionBinding(MCScriptInstanceRef p_instance,
857857
return MCScriptThrowObjCBindingNotImplemented();
858858
#endif
859859
}
860-
else if (MCStringIsEqualToCString(*t_language, "java", kMCStringOptionCompareExact))
860+
else if (MCStringIsEqualToCString(*t_language, "java", kMCStringOptionCompareExact) ||
861+
MCStringIsEqualToCString(*t_language, "javaui", kMCStringOptionCompareExact))
861862
{
863+
p_handler->is_ui_bound = MCStringIsEqualToCString(*t_language, "javaui", kMCStringOptionCompareExact);
864+
862865
p_handler -> is_java = true;
863866
p_handler->is_builtin = false;
864867

libscript/src/script-private.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ struct MCScriptForeignHandlerDefinition: public MCScriptCommonHandlerDefinition
342342

343343
// Bound function information - not pickled.
344344
bool is_java: 1;
345+
bool is_ui_bound : 1;
345346
bool is_bound: 1;
346347
bool is_builtin: 1;
347348

0 commit comments

Comments
 (0)