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"
/>
+