Skip to content

Commit

Permalink
platform/android-nosdl: Move all bindings to XashBindings class, work…
Browse files Browse the repository at this point in the history
…around broken messageBox from crashhandler
  • Loading branch information
mittorn committed Dec 1, 2023
1 parent 0a16388 commit adc3983
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 45 deletions.
102 changes: 66 additions & 36 deletions engine/platform/android/android_nosdl.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ GNU General Public License for more details.
#include "errno.h"
#include <pthread.h>
#include <sys/prctl.h>
#include <setjmp.h>

#ifndef JNICALL
#define JNICALL // a1ba: workaround for my IDE, where Java files are not included
Expand Down Expand Up @@ -162,6 +163,9 @@ static struct {
struct jnimethods_s jni;
struct jnimouse_s jnimouse;

static jmp_buf crash_frame, restore_frame;
char crash_text[1024];

#define Android_Lock() pthread_mutex_lock(&events.mutex);
#define Android_Unlock() pthread_mutex_unlock(&events.mutex);
#define Android_PushEvent() Android_Unlock()
Expand Down Expand Up @@ -206,7 +210,7 @@ nativeSetPause
*/
#define VA_ARGS(...) , ##__VA_ARGS__ // GCC extension
#define DECLARE_JNI_INTERFACE( ret, name, ... ) \
JNIEXPORT ret JNICALL Java_su_xash_engine_XashActivity_##name( JNIEnv *env, jclass clazz VA_ARGS(__VA_ARGS__) )
JNIEXPORT ret JNICALL Java_su_xash_engine_XashBinding_##name( JNIEnv *env, jclass clazz VA_ARGS(__VA_ARGS__) )

DECLARE_JNI_INTERFACE( int, nativeInit, jobject array )
{
Expand Down Expand Up @@ -242,26 +246,39 @@ DECLARE_JNI_INTERFACE( int, nativeInit, jobject array )
/* Init callbacks. */

jni.env = env;
jni.actcls = (*env)->FindClass(env, "su/xash/engine/XashActivity");
jni.enableTextInput = (*env)->GetStaticMethodID(env, jni.actcls, "showKeyboard", "(I)V");
jni.vibrate = (*env)->GetStaticMethodID(env, jni.actcls, "vibrate", "(I)V" );
jni.messageBox = (*env)->GetStaticMethodID(env, jni.actcls, "messageBox", "(Ljava/lang/String;Ljava/lang/String;)V");
jni.notify = (*env)->GetStaticMethodID(env, jni.actcls, "engineThreadNotify", "()V");
jni.setTitle = (*env)->GetStaticMethodID(env, jni.actcls, "setTitle", "(Ljava/lang/String;)V");
jni.setIcon = (*env)->GetStaticMethodID(env, jni.actcls, "setIcon", "(Ljava/lang/String;)V");
jni.getAndroidId = (*env)->GetStaticMethodID(env, jni.actcls, "getAndroidID", "()Ljava/lang/String;");
jni.saveID = (*env)->GetStaticMethodID(env, jni.actcls, "saveID", "(Ljava/lang/String;)V");
jni.loadID = (*env)->GetStaticMethodID(env, jni.actcls, "loadID", "()Ljava/lang/String;");
jni.showMouse = (*env)->GetStaticMethodID(env, jni.actcls, "showMouse", "(I)V");
jni.shellExecute = (*env)->GetStaticMethodID(env, jni.actcls, "shellExecute", "(Ljava/lang/String;)V");

jni.swapBuffers = (*env)->GetStaticMethodID(env, jni.actcls, "swapBuffers", "()V");
jni.toggleEGL = (*env)->GetStaticMethodID(env, jni.actcls, "toggleEGL", "(I)V");
jni.createGLContext = (*env)->GetStaticMethodID(env, jni.actcls, "createGLContext", "([I[I)Z");
jni.getGLAttribute = (*env)->GetStaticMethodID(env, jni.actcls, "getGLAttribute", "(I)I");
jni.deleteGLContext = (*env)->GetStaticMethodID(env, jni.actcls, "deleteGLContext", "()Z");
jni.getSelectedPixelFormat = (*env)->GetStaticMethodID(env, jni.actcls, "getSelectedPixelFormat", "()I");
jni.getSurface = (*env)->GetStaticMethodID(env, jni.actcls, "getNativeSurface", "(I)Landroid/view/Surface;");
jni.bindcls = (*env)->FindClass(env, "su/xash/engine/XashBinding");
jni.enableTextInput = (*env)->GetStaticMethodID(env, jni.bindcls, "showKeyboard", "(I)V");
jni.vibrate = (*env)->GetStaticMethodID(env, jni.bindcls, "vibrate", "(I)V" );
jni.messageBox = (*env)->GetStaticMethodID(env, jni.bindcls, "messageBox", "(Ljava/lang/String;Ljava/lang/String;)V");
jni.notify = (*env)->GetStaticMethodID(env, jni.bindcls, "engineThreadNotify", "()V");
jni.setTitle = (*env)->GetStaticMethodID(env, jni.bindcls, "setTitle", "(Ljava/lang/String;)V");
jni.setIcon = (*env)->GetStaticMethodID(env, jni.bindcls, "setIcon", "(Ljava/lang/String;)V");
jni.getAndroidId = (*env)->GetStaticMethodID(env, jni.bindcls, "getAndroidID", "()Ljava/lang/String;");
jni.saveID = (*env)->GetStaticMethodID(env, jni.bindcls, "saveID", "(Ljava/lang/String;)V");
jni.loadID = (*env)->GetStaticMethodID(env, jni.bindcls, "loadID", "()Ljava/lang/String;");
jni.showMouse = (*env)->GetStaticMethodID(env, jni.bindcls, "showMouse", "(I)V");
jni.shellExecute = (*env)->GetStaticMethodID(env, jni.bindcls, "shellExecute", "(Ljava/lang/String;)V");

jni.swapBuffers = (*env)->GetStaticMethodID(env, jni.bindcls, "swapBuffers", "()V");
jni.toggleEGL = (*env)->GetStaticMethodID(env, jni.bindcls, "toggleEGL", "(I)V");
jni.createGLContext = (*env)->GetStaticMethodID(env, jni.bindcls, "createGLContext", "([I[I)Z");
jni.getGLAttribute = (*env)->GetStaticMethodID(env, jni.bindcls, "getGLAttribute", "(I)I");
jni.deleteGLContext = (*env)->GetStaticMethodID(env, jni.bindcls, "deleteGLContext", "()Z");
jni.getSurface = (*env)->GetStaticMethodID(env, jni.bindcls, "getNativeSurface", "(I)Landroid/view/Surface;");

// jni fails when called from signal handler callback, so jump here when called messagebox from handler
if( setjmp( crash_frame ))
{
// note: this will destroy stack and shutting down engine with return-from-main
// will be impossible, but Sys_Quit works
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.messageBox, (*jni.env)->NewStringUTF( jni.env, "crash" ), (*jni.env)->NewStringUTF( jni.env , crash_text ) );

// java shutdown callback here?

// UB, but who cares, we already crashed!
longjmp( restore_frame, 1 );
return 127; // unreach
}

/* Run the application. */

Expand Down Expand Up @@ -598,7 +615,9 @@ Show virtual keyboard
*/
void Platform_EnableTextInput( qboolean enable )
{
(*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.enableTextInput, enable );
if( host.crashed )
return;
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.enableTextInput, enable );
}

/*
Expand All @@ -609,7 +628,7 @@ Android_Vibrate
void Platform_Vibrate( float life, char flags )
{
if( life )
(*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.vibrate, (int)life );
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.vibrate, (int)life );
}

/*
Expand All @@ -632,6 +651,8 @@ void *Android_GetNativeObject( const char *objName )
}
else if( !strcasecmp( objName, "ActivityClass" ) )
{
if( !jni.actcls )
jni.actcls = (*jni.env)->FindClass( jni.env, "su/xash/engine/XashActivity" );
object = (void*)jni.actcls;
}

Expand All @@ -648,7 +669,16 @@ Show messagebox and wait for OK button press
#if XASH_MESSAGEBOX == MSGBOX_ANDROID
void Platform_MessageBox( const char *title, const char *text, qboolean parentMainWindow )
{
(*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.messageBox, (*jni.env)->NewStringUTF( jni.env, title ), (*jni.env)->NewStringUTF( jni.env ,text ) );
// jni calls from signal handler broken since some android version, so move to "safe" frame and pass text
if( host.crashed )
{
if( setjmp( restore_frame ) )
return;
Q_strncpy( crash_text, text, 1024 );
longjmp( crash_frame, 1 );
return;
}
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.messageBox, (*jni.env)->NewStringUTF( jni.env, title ), (*jni.env)->NewStringUTF( jni.env ,text ) );
}
#endif // XASH_MESSAGEBOX == MSGBOX_ANDROID

Expand All @@ -666,7 +696,7 @@ const char *Android_GetAndroidID( void )
if( id[0] )
return id;

resultJNIStr = (jstring)(*jni.env)->CallStaticObjectMethod( jni.env, jni.actcls, jni.getAndroidId );
resultJNIStr = (jstring)(*jni.env)->CallStaticObjectMethod( jni.env, jni.bindcls, jni.getAndroidId );
resultCStr = (*jni.env)->GetStringUTFChars( jni.env, resultJNIStr, NULL );
Q_strncpy( id, resultCStr, 64 );
(*jni.env)->ReleaseStringUTFChars( jni.env, resultJNIStr, resultCStr );
Expand All @@ -685,7 +715,7 @@ Android_LoadID
const char *Android_LoadID( void )
{
static char id[65];
jstring resultJNIStr = (jstring)(*jni.env)->CallStaticObjectMethod( jni.env, jni.actcls, jni.loadID );
jstring resultJNIStr = (jstring)(*jni.env)->CallStaticObjectMethod( jni.env, jni.bindcls, jni.loadID );
const char *resultCStr = (*jni.env)->GetStringUTFChars( jni.env, resultJNIStr, NULL );
Q_strncpy( id, resultCStr, 64 );
(*jni.env)->ReleaseStringUTFChars( jni.env, resultJNIStr, resultCStr );
Expand All @@ -699,7 +729,7 @@ Android_SaveID
*/
void Android_SaveID( const char *id )
{
(*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.saveID, (*jni.env)->NewStringUTF( jni.env, id ) );
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.saveID, (*jni.env)->NewStringUTF( jni.env, id ) );
}

/*
Expand Down Expand Up @@ -752,7 +782,7 @@ void Android_ShowMouse( qboolean show )
{
if( m_ignore.value )
show = true;
(*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.showMouse, show );
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.showMouse, show );
}

/*
Expand All @@ -771,7 +801,7 @@ void Platform_ShellExecute( const char *path, const char *parms )
jstr = (*jni.env)->NewStringUTF( jni.env, path );

// open browser
(*jni.env)->CallStaticVoidMethod(jni.env, jni.actcls, jni.shellExecute, jstr);
(*jni.env)->CallStaticVoidMethod(jni.env, jni.bindcls, jni.shellExecute, jstr);

// no need to free jstr
}
Expand Down Expand Up @@ -858,7 +888,7 @@ static void Android_ProcessEvents( void )
if( !events.queue[i].arg )
{
SNDDMA_Activate( true );
// (*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.toggleEGL, 1 );
// (*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.toggleEGL, 1 );
Android_UpdateSurface( surface_active );
SetBits( gl_vsync.flags, FCVAR_CHANGED ); // set swap interval
host.force_draw_version_time = host.realtime + FORCE_DRAW_VERSION_TIME;
Expand All @@ -868,17 +898,17 @@ static void Android_ProcessEvents( void )
{
SNDDMA_Activate( false );
Android_UpdateSurface( !android_sleep->value ? surface_dummy : surface_pause );
// (*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.toggleEGL, 0 );
// (*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.toggleEGL, 0 );
}
(*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.notify );
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.notify );
break;

case event_resize:
// reinitialize EGL and change engine screen size
if( ( host.status == HOST_FRAME || host.status == HOST_NOFOCUS ) &&( refState.width != jni.width || refState.height != jni.height ))
{
// (*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.toggleEGL, 0 );
// (*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.toggleEGL, 1 );
// (*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.toggleEGL, 0 );
// (*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.toggleEGL, 1 );
Con_DPrintf("resize event\n");
Android_UpdateSurface( surface_pause );
Android_UpdateSurface( surface_active );
Expand Down Expand Up @@ -920,7 +950,7 @@ static void Android_ProcessEvents( void )
case event_ondestroy:
//host.skip_configs = true; // skip config save, because engine may be killed during config save
Sys_Quit();
(*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.notify );
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.notify );
break;
case event_onpause:
#ifdef PARANOID_CONFIG_SAVE
Expand All @@ -941,7 +971,7 @@ static void Android_ProcessEvents( void )
SNDDMA_Activate( false );
//host.status = HOST_SLEEP;
// stop blocking UI thread
(*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.notify );
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.notify );

break;
case event_onresume:
Expand Down
2 changes: 1 addition & 1 deletion engine/platform/android/android_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
extern struct jnimethods_s
{
jclass actcls;
jclass bindcls;
JavaVM *vm;
JNIEnv *env;
jmethodID enableTextInput;
Expand All @@ -27,7 +28,6 @@ extern struct jnimethods_s
jmethodID createGLContext;
jmethodID getGLAttribute;
jmethodID deleteGLContext;
jmethodID getSelectedPixelFormat;
jmethodID getSurface;
int width, height;
} jni;
Expand Down
16 changes: 8 additions & 8 deletions engine/platform/android/vid_android.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ Android_SetTitle
*/
static void Android_SetTitle( const char *title )
{
(*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.setTitle, (*jni.env)->NewStringUTF( jni.env, title ) );
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.setTitle, (*jni.env)->NewStringUTF( jni.env, title ) );
}

/*
Expand All @@ -78,7 +78,7 @@ Android_SetIcon
*/
static void Android_SetIcon( const char *path )
{
(*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.setIcon, (*jni.env)->NewStringUTF( jni.env, path ) );
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.setIcon, (*jni.env)->NewStringUTF( jni.env, path ) );
}

/*
Expand Down Expand Up @@ -108,7 +108,7 @@ void GL_SwapBuffers( void )
}
else
{
(*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.swapBuffers );
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.swapBuffers );
}
}

Expand Down Expand Up @@ -147,7 +147,7 @@ void Android_UpdateSurface( surfacestate_t state )
jobject surf;
if( vid_android.window )
nw.release( vid_android.window );
surf = (*jni.env)->CallStaticObjectMethod( jni.env, jni.actcls, jni.getSurface, state );
surf = (*jni.env)->CallStaticObjectMethod( jni.env, jni.bindcls, jni.getSurface, state );
Con_DPrintf("Surface handle %p\n", surf);
if( surf )
{
Expand All @@ -174,7 +174,7 @@ void Android_UpdateSurface( surfacestate_t state )
if( !vid_android.has_context )
return;

(*jni.env)->CallStaticVoidMethod( jni.env, jni.actcls, jni.toggleEGL, (int)state );
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.toggleEGL, (int)state );
host.status = HOST_FRAME; // active ? HOST_FRAME : HOST_SLEEP;

// todo: check opengl context here and set HOST_SLEEP if not
Expand All @@ -194,7 +194,7 @@ Android_GetGLAttribute
*/
static int Android_GetGLAttribute( int eglAttr )
{
int ret = (*jni.env)->CallStaticIntMethod( jni.env, jni.actcls, jni.getGLAttribute, eglAttr );
int ret = (*jni.env)->CallStaticIntMethod( jni.env, jni.bindcls, jni.getGLAttribute, eglAttr );
// Con_Reportf( "Android_GetGLAttribute( %i ) => %i\n", eglAttr, ret );
return ret;
}
Expand Down Expand Up @@ -276,7 +276,7 @@ qboolean R_Init_Video( const int type )

void R_Free_Video( void )
{
// (*jni.env)->CallStaticBooleanMethod( jni.env, jni.actcls, jni.deleteGLContext );
// (*jni.env)->CallStaticBooleanMethod( jni.env, jni.bindcls, jni.deleteGLContext );

// VID_DestroyWindow ();

Expand Down Expand Up @@ -348,7 +348,7 @@ qboolean VID_SetMode( void )
R_ChangeDisplaySettings( 0, 0, WINDOW_MODE_WINDOWED ); // width and height are ignored anyway


if( (*jni.env)->CallStaticBooleanMethod( jni.env, jni.actcls, jni.createGLContext, attribs, contextAttribs ) )
if( (*jni.env)->CallStaticBooleanMethod( jni.env, jni.bindcls, jni.createGLContext, attribs, contextAttribs ) )
{
vid_android.has_context = true;
return true;
Expand Down

0 comments on commit adc3983

Please sign in to comment.