diff --git a/xwords4/android/XWords4/jni/Android.mk b/xwords4/android/XWords4/jni/Android.mk index 215e88fd3..f026e552c 100644 --- a/xwords4/android/XWords4/jni/Android.mk +++ b/xwords4/android/XWords4/jni/Android.mk @@ -4,17 +4,17 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) COMMON_PATH=../../../common -local_C_INCLUDES+= \ +LOCAL_C_INCLUDES+= \ -I$(LOCAL_PATH)/$(COMMON_PATH) \ -I$(LOCAL_PATH)/../../../relay \ -local_LDLIBS += -llog +LOCAL_LDLIBS += -llog ifeq ($(BUILD_TARGET),debug) - local_DEBUG = -DMEM_DEBUG -DDEBUG -DENABLE_LOGGING -DCOMMS_CHECKSUM -Wno-unused-but-set-variable + LOCAL_DEBUG = -DMEM_DEBUG -DDEBUG -DENABLE_LOGGING -DCOMMS_CHECKSUM -Wno-unused-but-set-variable endif -local_DEFINES += \ - $(local_DEBUG) \ +LOCAL_DEFINES += \ + $(LOCAL_DEBUG) \ -DXWFEATURE_RELAY \ -DXWFEATURE_SMS \ -DXWFEATURE_COMMSACK \ @@ -37,12 +37,14 @@ local_DEFINES += \ -DHASH_STREAM \ -DXWFEATURE_BASE64 \ -DXWFEATURE_DEVID \ + -DCOMMON_LAYOUT \ -DINITIAL_CLIENT_VERS=${INITIAL_CLIENT_VERS} \ -DRELAY_ROOM_DEFAULT=\"\" \ -D__LITTLE_ENDIAN \ ifeq ($(CHAT_ENABLED),true) - local_DEFINES += -DXWFEATURE_CHAT + + LOCAL_DEFINES += -DXWFEATURE_CHAT endif ifeq ($(THUMBNAIL_ENABLED),true) local_DEFINES += -DXWFEATURE_ACTIVERECT @@ -50,7 +52,7 @@ endif # -DXWFEATURE_SCOREONEPASS \ -local_SRC_FILES += \ +LOCAL_SRC_FILES += \ xwjni.c \ utilwrapper.c \ drawwrapper.c \ @@ -61,7 +63,7 @@ local_SRC_FILES += \ COMMON_PATH=../../../common -common_SRC_FILES += \ +COMMON_SRC_FILES += \ $(COMMON_PATH)/boarddrw.c \ $(COMMON_PATH)/scorebdp.c \ $(COMMON_PATH)/dragdrpp.c \ @@ -84,9 +86,12 @@ common_SRC_FILES += \ $(COMMON_PATH)/dbgutil.c \ -LOCAL_CFLAGS+=$(local_C_INCLUDES) $(local_DEFINES) -Wall -LOCAL_SRC_FILES := $(linux_SRC_FILES) $(local_SRC_FILES) $(common_SRC_FILES) +LOCAL_CFLAGS+=$(LOCAL_C_INCLUDES) $(LOCAL_DEFINES) +LOCAL_SRC_FILES := $(linux_SRC_FILES) $(LOCAL_SRC_FILES) $(COMMON_SRC_FILES) LOCAL_MODULE := xwjni LOCAL_LDLIBS := -L${SYSROOT}/usr/lib -llog -lz include $(BUILD_SHARED_LIBRARY) + +COMMON_SRC_FILES := +COMMON_PATH := diff --git a/xwords4/android/XWords4/jni/Application.mk b/xwords4/android/XWords4/jni/Application.mk new file mode 100644 index 000000000..7a1599bb9 --- /dev/null +++ b/xwords4/android/XWords4/jni/Application.mk @@ -0,0 +1 @@ +APP_ABI := armeabi x86 diff --git a/xwords4/android/XWords4/jni/andutils.c b/xwords4/android/XWords4/jni/andutils.c index 0f96028aa..4ef50d5ae 100644 --- a/xwords4/android/XWords4/jni/andutils.c +++ b/xwords4/android/XWords4/jni/andutils.c @@ -88,6 +88,30 @@ getInt( JNIEnv* env, jobject obj, const char* name ) return result; } +void +getInts( JNIEnv* env, void* cobj, jobject jobj, const SetInfo* sis, XP_U16 nSis ) +{ + int ii; + for ( ii = 0; ii < nSis; ++ii ) { + const SetInfo* si = &sis[ii]; + uint8_t* ptr = ((uint8_t*)cobj) + si->offset; + int val = getInt( env, jobj, si->name ); + switch( si->siz ) { + case 4: + *(uint32_t*)ptr = val; + break; + case 2: + *(uint16_t*)ptr = val; + break; + case 1: + *ptr = val; + break; + } + /* XP_LOGF( "%s: wrote int %s of size %d with val %d at offset %d", */ + /* __func__, si->name, si->siz, val, si->offset ); */ + } +} + void setInt( JNIEnv* env, jobject obj, const char* name, int value ) { @@ -99,6 +123,34 @@ setInt( JNIEnv* env, jobject obj, const char* name, int value ) deleteLocalRef( env, cls ); } +void +setInts( JNIEnv* env, jobject jobj, void* cobj, const SetInfo* sis, XP_U16 nSis ) +{ + int ii; + for ( ii = 0; ii < nSis; ++ii ) { + const SetInfo* si = &sis[ii]; + uint8_t* ptr = ((uint8_t*)cobj) + si->offset; + int val; + switch( si->siz ) { + case 4: + val = *(uint32_t*)ptr; + break; + case 2: + val = *(uint16_t*)ptr; + break; + case 1: + val = *ptr; + break; + default: + val = 0; + XP_ASSERT(0); + } + setInt( env, jobj, si->name, val ); + /* XP_LOGF( "%s: read int %s of size %d with val %d from offset %d", */ + /* __func__, si->name, si->siz, val, si->offset ); */ + } +} + bool setBool( JNIEnv* env, jobject obj, const char* name, bool value ) { @@ -114,6 +166,19 @@ setBool( JNIEnv* env, jobject obj, const char* name, bool value ) return success; } +void +setBools( JNIEnv* env, jobject jobj, void* cobj, const SetInfo* sis, XP_U16 nSis ) +{ + int ii; + for ( ii = 0; ii < nSis; ++ii ) { + const SetInfo* si = &sis[ii]; + XP_Bool val = *(XP_Bool*)(((uint8_t*)cobj)+si->offset); + setBool( env, jobj, si->name, val ); + /* XP_LOGF( "%s: read bool %s with val %d from offset %d", __func__, */ + /* si->name, val, si->offset ); */ + } +} + bool setString( JNIEnv* env, jobject obj, const char* name, const XP_UCHAR* value ) { @@ -210,6 +275,19 @@ getBool( JNIEnv* env, jobject obj, const char* name ) return result; } +void +getBools( JNIEnv* env, void* cobj, jobject jobj, const SetInfo* sis, XP_U16 nSis ) +{ + int ii; + for ( ii = 0; ii < nSis; ++ii ) { + const SetInfo* si = &sis[ii]; + XP_Bool val = getBool( env, jobj, si->name ); + *(XP_Bool*)(((uint8_t*)cobj)+si->offset) = val; + /* XP_LOGF( "%s: wrote bool %s with val %d at offset %d", __func__, */ + /* si->name, val, si->offset ); */ + } +} + jintArray makeIntArray( JNIEnv *env, int siz, const jint* vals ) { diff --git a/xwords4/android/XWords4/jni/andutils.h b/xwords4/android/XWords4/jni/andutils.h index 82a037714..14d94a559 100644 --- a/xwords4/android/XWords4/jni/andutils.h +++ b/xwords4/android/XWords4/jni/andutils.h @@ -33,10 +33,28 @@ void and_send_on_close( XWStreamCtxt* stream, void* closure ); XWStreamCtxt* and_empty_stream( MPFORMAL AndGlobals* globals ); +typedef struct _SetInfo { + const char* name; + int offset; + int siz; +} SetInfo; +#define ARR_MEMBER(obj, fld) { .name = #fld, \ + .offset = OFFSET_OF(obj, fld), \ + .siz = sizeof(((obj *)0)->fld) \ + } + int getInt( JNIEnv* env, jobject obj, const char* name ); void setInt( JNIEnv* env, jobject obj, const char* name, int value ); +void setInts( JNIEnv* env, jobject jobj, void* cobj, + const SetInfo* sis, XP_U16 nSis ); +void getInts( JNIEnv* env, void* cobj, jobject jobj, + const SetInfo* sis, XP_U16 nSis ); bool getBool( JNIEnv* env, jobject obj, const char* name ); +void getBools( JNIEnv* env, void* cobj, jobject jobj, + const SetInfo* sis, XP_U16 nSis ); bool setBool( JNIEnv* env, jobject obj, const char* name, bool value ); +void setBools( JNIEnv* env, jobject jobj, void* cobj, + const SetInfo* sis, XP_U16 nSis ); bool setString( JNIEnv* env, jobject obj, const char* name, const XP_UCHAR* value ); void getString( JNIEnv* env, jobject jlp, const char* name, XP_UCHAR* buf, int bufLen ); diff --git a/xwords4/android/XWords4/jni/xwjni.c b/xwords4/android/XWords4/jni/xwjni.c index 3d0dd540b..5192cf332 100644 --- a/xwords4/android/XWords4/jni/xwjni.c +++ b/xwords4/android/XWords4/jni/xwjni.c @@ -39,47 +39,54 @@ #include "jniutlswrapper.h" #include "paths.h" +static const SetInfo gi_ints[] = { + ARR_MEMBER( CurGameInfo, nPlayers ) + ,ARR_MEMBER( CurGameInfo, gameSeconds ) + ,ARR_MEMBER( CurGameInfo, boardSize ) + ,ARR_MEMBER( CurGameInfo, gameID ) + ,ARR_MEMBER( CurGameInfo, dictLang ) +}; + +static const SetInfo gi_bools[] = { + ARR_MEMBER( CurGameInfo, hintsNotAllowed ) + ,ARR_MEMBER( CurGameInfo, timerEnabled ) + ,ARR_MEMBER( CurGameInfo, allowPickTiles ) + ,ARR_MEMBER( CurGameInfo, allowHintRect ) +}; + static CurGameInfo* -makeGI( MPFORMAL JNIEnv* env, jobject j_gi ) +makeGI( MPFORMAL JNIEnv* env, jobject jgi ) { CurGameInfo* gi = (CurGameInfo*)XP_CALLOC( mpool, sizeof(*gi) ); XP_UCHAR buf[256]; /* in case needs whole path */ - gi->nPlayers = getInt( env, j_gi, "nPlayers"); - gi->gameSeconds = getInt( env, j_gi, "gameSeconds"); - gi->boardSize = getInt( env, j_gi, "boardSize" ); + getInts( env, (void*)gi, jgi, gi_ints, VSIZE(gi_ints) ); + getBools( env, (void*)gi, jgi, gi_bools, VSIZE(gi_bools) ); /* Unlike on other platforms, gi is created without a call to game_makeNewGame, which sets gameID. So check here if it's still unset and if necessary set it -- including back in the java world. */ - gi->gameID = getInt( env, j_gi, "gameID" ); if ( 0 == gi->gameID ) { while ( 0 == gi->gameID ) { gi->gameID = getCurSeconds( env ); } - setInt( env, j_gi, "gameID", gi->gameID ); + setInt( env, jgi, "gameID", gi->gameID ); } - gi->dictLang = getInt( env, j_gi, "dictLang" ); - gi->hintsNotAllowed = getBool( env, j_gi, "hintsNotAllowed" ); - gi->timerEnabled = getBool( env, j_gi, "timerEnabled" ); - gi->allowPickTiles = getBool( env, j_gi, "allowPickTiles" ); - gi->allowHintRect = getBool( env, j_gi, "allowHintRect" ); - gi->phoniesAction = - jenumFieldToInt( env, j_gi, "phoniesAction", + jenumFieldToInt( env, jgi, "phoniesAction", PKG_PATH("jni/CurGameInfo$XWPhoniesChoice") ); gi->serverRole = - jenumFieldToInt( env, j_gi, "serverRole", + jenumFieldToInt( env, jgi, "serverRole", PKG_PATH("jni/CurGameInfo$DeviceRole")); - getString( env, j_gi, "dictName", buf, VSIZE(buf) ); + getString( env, jgi, "dictName", buf, VSIZE(buf) ); gi->dictName = copyString( mpool, buf ); XP_ASSERT( gi->nPlayers <= MAX_NUM_PLAYERS ); jobject jplayers; - if ( getObject( env, j_gi, "players", "[L" PKG_PATH("jni/LocalPlayer") ";", + if ( getObject( env, jgi, "players", "[L" PKG_PATH("jni/LocalPlayer") ";", &jplayers ) ) { int ii; for ( ii = 0; ii < gi->nPlayers; ++ii ) { @@ -114,14 +121,10 @@ static void setJGI( JNIEnv* env, jobject jgi, const CurGameInfo* gi ) { // set fields - setInt( env, jgi, "nPlayers", gi->nPlayers ); - setInt( env, jgi, "gameSeconds", gi->gameSeconds ); - setInt( env, jgi, "boardSize", gi->boardSize ); - setInt( env, jgi, "gameID", gi->gameID ); - setInt( env, jgi, "dictLang", gi->dictLang ); - setBool( env, jgi, "hintsNotAllowed", gi->hintsNotAllowed ); - setBool( env, jgi, "timerEnabled", gi->timerEnabled ); - setBool( env, jgi, "allowPickTiles", gi->allowPickTiles ); + + setInts( env, jgi, (void*)gi, gi_ints, VSIZE(gi_ints) ); + setBools( env, jgi, (void*)gi, gi_bools, VSIZE(gi_bools) ); + setString( env, jgi, "dictName", gi->dictName ); intToJenumField( env, jgi, gi->phoniesAction, "phoniesAction", @@ -155,6 +158,36 @@ setJGI( JNIEnv* env, jobject jgi, const CurGameInfo* gi ) } } /* setJGI */ +#ifdef COMMON_LAYOUT +static const SetInfo bd_ints[] = { + ARR_MEMBER( BoardDims, left ) + ,ARR_MEMBER( BoardDims, top ) + ,ARR_MEMBER( BoardDims, width ) + ,ARR_MEMBER( BoardDims, height ) + ,ARR_MEMBER( BoardDims, scoreHt ) + ,ARR_MEMBER( BoardDims, boardHt ) + ,ARR_MEMBER( BoardDims, trayTop ) + ,ARR_MEMBER( BoardDims, trayHt ) + ,ARR_MEMBER( BoardDims, cellSize ) + ,ARR_MEMBER( BoardDims, maxCellSize ) + ,ARR_MEMBER( BoardDims, timerWidth ) +}; + +static void +dimsJToC( JNIEnv* env, BoardDims* out, jobject jdims ) +{ + getInts( env, (void*)out, jdims, bd_ints, VSIZE(bd_ints) ); +} + +static void +dimsCtoJ( JNIEnv* env, jobject jdims, const BoardDims* in ) +{ + LOG_FUNC(); + setInts( env, jdims, (void*)in, bd_ints, VSIZE(bd_ints) ); + LOG_RETURN_VOID(); +} +#endif + static void destroyGI( MPFORMAL CurGameInfo** gip ) { @@ -598,6 +631,47 @@ Java_org_eehouse_android_xw4_jni_XwJNI_board_1draw return result; } +#ifdef COMMON_LAYOUT +JNIEXPORT void JNICALL +Java_org_eehouse_android_xw4_jni_XwJNI_board_1figureLayout +( JNIEnv* env, jclass C, jint gamePtr, jobject jgi, jint fontHt, jint fontWidth, + jboolean squareTiles, jobject jbounds, jobject jdims ) +{ + LOG_FUNC(); + XWJNI_START(); + CurGameInfo* gi = makeGI( MPPARM(mpool) env, jgi ); + + XP_Rect bounds; + bounds.left = getInt( env, jbounds, "left" ); + bounds.top = getInt( env, jbounds, "top" ); + bounds.width = getInt( env, jbounds, "right" ) - bounds.left; + bounds.height = getInt( env, jbounds, "bottom" ) - bounds.top; + + BoardDims dims; + board_figureLayout( state->game.board, gi, 150, 200, fontHt, fontWidth, + squareTiles, &bounds, ((!!jdims) ? &dims : NULL) ); + + destroyGI( MPPARM(mpool) &gi ); + + if ( !!jdims ) { + dimsCtoJ( env, jdims, &dims ); + } + XWJNI_END(); + LOG_RETURN_VOID(); +} + +JNIEXPORT void JNICALL +Java_org_eehouse_android_xw4_jni_XwJNI_board_1applyLayout +( JNIEnv* env, jclass C, jint gamePtr, jobject jdims ) +{ + XWJNI_START(); + BoardDims dims; + dimsJToC( env, &dims, jdims ); + board_applyLayout( state->game.board, &dims ); + XWJNI_END(); +} +#endif + JNIEXPORT void JNICALL Java_org_eehouse_android_xw4_jni_XwJNI_board_1setPos (JNIEnv *env, jclass C, jint gamePtr, jint left, jint top, jint width, diff --git a/xwords4/android/XWords4/res/values/common_rsrc.xml b/xwords4/android/XWords4/res/values/common_rsrc.xml index eb45a31af..fcbffe4c8 100644 --- a/xwords4/android/XWords4/res/values/common_rsrc.xml +++ b/xwords4/android/XWords4/res/values/common_rsrc.xml @@ -104,6 +104,7 @@ key_na_browseall key_na_values key_enable_debug + key_enable_commlayt key_download_path diff --git a/xwords4/android/XWords4/res/xml/xwprefs.xml b/xwords4/android/XWords4/res/xml/xwprefs.xml index e2a2ca483..6d1564a4b 100644 --- a/xwords4/android/XWords4/res/xml/xwprefs.xml +++ b/xwords4/android/XWords4/res/xml/xwprefs.xml @@ -307,6 +307,11 @@ android:summary="Menuitems etc." android:defaultValue="false" /> +