diff --git a/xwords4/android/XWords4/jni/Android.mk b/xwords4/android/XWords4/jni/Android.mk index 84e0f686f..45bef2dcb 100644 --- a/xwords4/android/XWords4/jni/Android.mk +++ b/xwords4/android/XWords4/jni/Android.mk @@ -32,6 +32,7 @@ local_SRC_FILES += \ xportwrapper.c \ anddict.c \ andutils.c \ + jniutlswrapper.c \ COMMON_PATH=../../../common diff --git a/xwords4/android/XWords4/jni/anddict.c b/xwords4/android/XWords4/jni/anddict.c index 0c8a8561e..2431c90f6 100644 --- a/xwords4/android/XWords4/jni/anddict.c +++ b/xwords4/android/XWords4/jni/anddict.c @@ -8,11 +8,12 @@ #include "xptypes.h" #include "dictnry.h" #include "strutils.h" +#include "andutils.h" #include "utilwrapper.h" typedef struct _AndDictionaryCtxt { DictionaryCtxt super; - XW_UtilCtxt* util; + JNIUtilCtxt* jniutil; JNIEnv *env; XP_U8* bytes; } AndDictionaryCtxt; @@ -22,7 +23,8 @@ dict_splitFaces( DictionaryCtxt* dict, const XP_U8* bytes, XP_U16 nBytes, XP_U16 nFaces ) { XP_UCHAR* faces = (XP_UCHAR*)XP_CALLOC( dict->mpool, nBytes + nFaces ); - XP_UCHAR** ptrs = (XP_UCHAR**)XP_CALLOC( dict->mpool, nFaces * sizeof(ptrs[0])); + const XP_UCHAR** ptrs = (const XP_UCHAR**) + XP_CALLOC( dict->mpool, nFaces * sizeof(ptrs[0])); XP_U16 ii; XP_UCHAR* next = faces; @@ -112,7 +114,7 @@ andMakeBitmap( AndDictionaryCtxt* ctxt, XP_U8** ptrp ) } JNIEnv* env = ctxt->env; - bitmap = and_util_makeJBitmap( ctxt->util, nCols, nRows, colors ); + bitmap = and_util_makeJBitmap( ctxt->jniutil, nCols, nRows, colors ); jobject tmp = (*env)->NewGlobalRef( env, bitmap ); XP_ASSERT( tmp == bitmap ); (*env)->DeleteLocalRef( env, bitmap ); @@ -176,7 +178,7 @@ splitFaces_via_java( JNIEnv* env, AndDictionaryCtxt* ctxt, const XP_U8* ptr, int nBytes; int ii; - jobject jstrarr = and_util_splitFaces( ctxt->util, ptr, nFaceBytes ); + jobject jstrarr = and_util_splitFaces( ctxt->jniutil, ptr, nFaceBytes ); XP_ASSERT( (*env)->GetArrayLength( env, jstrarr ) == nFaces ); for ( ii = 0; ii < nFaces; ++ii ) { @@ -204,8 +206,8 @@ splitFaces_via_java( JNIEnv* env, AndDictionaryCtxt* ctxt, const XP_U8* ptr, (*env)->DeleteLocalRef( env, jstrarr ); XP_UCHAR* faces = (XP_UCHAR*)XP_CALLOC( ctxt->super.mpool, indx ); - XP_UCHAR** ptrs = (XP_UCHAR**)XP_CALLOC( ctxt->super.mpool, - nFaces * sizeof(ptrs[0])); + const XP_UCHAR** ptrs = (const XP_UCHAR**) + XP_CALLOC( ctxt->super.mpool, nFaces * sizeof(ptrs[0])); XP_MEMCPY( faces, facesBuf, indx ); for ( ii = 0; ii < nFaces; ++ii ) { @@ -373,6 +375,20 @@ and_dictionary_destroy( DictionaryCtxt* dict ) LOG_RETURN_VOID(); } +jobject +and_dictionary_getChars( JNIEnv* env, DictionaryCtxt* dict ) +{ + AndDictionaryCtxt* anddict = (AndDictionaryCtxt*)dict; + XP_ASSERT( env == anddict->env ); + + /* This is cheating: specials will be rep'd as 1,2, etc. But as long as + java code wants to ignore them anyway that's ok. Otherwise need to + use dict_tilesToString() */ + XP_U16 nFaces = dict_numTileFaces( dict ); + jobject jstrs = makeStringArray( env, nFaces, dict->facePtrs ); + return jstrs; +} + DictionaryCtxt* and_dictionary_make_empty( MPFORMAL_NOCOMMA ) { @@ -384,7 +400,7 @@ and_dictionary_make_empty( MPFORMAL_NOCOMMA ) } DictionaryCtxt* -makeDict( MPFORMAL JNIEnv *env, XW_UtilCtxt* util, jbyteArray jbytes ) +makeDict( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil, jbyteArray jbytes ) { XP_Bool formatOk = XP_TRUE; XP_Bool isUTF8 = XP_FALSE; @@ -392,7 +408,6 @@ makeDict( MPFORMAL JNIEnv *env, XW_UtilCtxt* util, jbyteArray jbytes ) AndDictionaryCtxt* anddict = NULL; jsize len = (*env)->GetArrayLength( env, jbytes ); - XP_LOGF( "%s: got %d bytes", __func__, len ); XP_U8* localBytes = XP_MALLOC( mpool, len ); jbyte* src = (*env)->GetByteArrayElements( env, jbytes, NULL ); @@ -406,7 +421,7 @@ makeDict( MPFORMAL JNIEnv *env, XW_UtilCtxt* util, jbyteArray jbytes ) anddict->bytes = localBytes; anddict->env = env; - anddict->util = util; + anddict->jniutil = jniutil; parseDict( anddict, localBytes, len ); setBlankTile( &anddict->super ); diff --git a/xwords4/android/XWords4/jni/anddict.h b/xwords4/android/XWords4/jni/anddict.h index 42a865537..c5395d196 100644 --- a/xwords4/android/XWords4/jni/anddict.h +++ b/xwords4/android/XWords4/jni/anddict.h @@ -5,14 +5,17 @@ #include "dictnry.h" #include "comtypes.h" +#include "jniutlswrapper.h" void dict_splitFaces( DictionaryCtxt* dict, const XP_U8* bytes, XP_U16 nBytes, XP_U16 nFaces ); -DictionaryCtxt* makeDict( MPFORMAL JNIEnv *env, XW_UtilCtxt* util, +DictionaryCtxt* makeDict( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil, jbyteArray bytes ); DictionaryCtxt* and_dictionary_make_empty( MPFORMAL_NOCOMMA ); +jobject and_dictionary_getChars( JNIEnv* env, DictionaryCtxt* dict ); + #endif diff --git a/xwords4/android/XWords4/jni/andglobals.h b/xwords4/android/XWords4/jni/andglobals.h index 79f82c969..b8466b1e0 100644 --- a/xwords4/android/XWords4/jni/andglobals.h +++ b/xwords4/android/XWords4/jni/andglobals.h @@ -11,6 +11,7 @@ typedef struct _AndGlobals { CurGameInfo* gi; DrawCtx* dctx; XW_UtilCtxt* util; + struct JNIUtilCtxt* jniutil; TransportProcs* xportProcs; struct JNIState* state; } AndGlobals; diff --git a/xwords4/android/XWords4/jni/drawwrapper.c b/xwords4/android/XWords4/jni/drawwrapper.c index 62631c2eb..582ec4410 100644 --- a/xwords4/android/XWords4/jni/drawwrapper.c +++ b/xwords4/android/XWords4/jni/drawwrapper.c @@ -109,6 +109,7 @@ makeDSI( AndDraw* draw, int indx, const DrawScoreInfo* dsi ) #define DRAW_CBK_HEADER(nam,sig) \ AndDraw* draw = (AndDraw*)dctx; \ JNIEnv* env = *draw->env; \ + XP_ASSERT( !!draw->jdraw ); \ jmethodID mid = getMethodID( env, draw->jdraw, nam, sig ); static void @@ -209,7 +210,9 @@ and_draw_score_drawPlayer( DrawCtx* dctx, static XP_Bool and_draw_boardBegin( DrawCtx* dctx, const XP_Rect* rect, DrawFocusState dfs ) { - return XP_TRUE; + AndDraw* draw = (AndDraw*)dctx; + XP_Bool result = NULL != draw->jdraw; + return result; } static XP_Bool @@ -380,7 +383,11 @@ and_draw_objFinished( DrawCtx* dctx, BoardObjectType typ, static void and_draw_dictChanged( DrawCtx* dctx, const DictionaryCtxt* dict ) { - LOG_FUNC(); + AndDraw* draw = (AndDraw*)dctx; + if ( NULL != draw->jdraw ) { + DRAW_CBK_HEADER( "dictChanged", "(I)V" ); + (*env)->CallVoidMethod( env, draw->jdraw, mid, (jint)dict ); + } } static const XP_UCHAR* diff --git a/xwords4/android/XWords4/jni/jniutlswrapper.c b/xwords4/android/XWords4/jni/jniutlswrapper.c new file mode 100644 index 000000000..aa733527a --- /dev/null +++ b/xwords4/android/XWords4/jni/jniutlswrapper.c @@ -0,0 +1,93 @@ +/* -*-mode: C; compile-command: "../../scripts/ndkbuild.sh"; -*- */ +/* + * Copyright 2001-2010 by Eric House (xwords@eehouse.org). All rights + * reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "strutils.h" +#include "jniutlswrapper.h" +#include "andutils.h" + + +struct JNIUtilCtxt { + JNIEnv** envp; + jobject jjniutil; + MPSLOT; +}; + +JNIUtilCtxt* +makeJNIUtil( MPFORMAL JNIEnv** envp, jobject jniutls ) +{ + JNIUtilCtxt* ctxt = (JNIUtilCtxt*)XP_CALLOC( mpool, sizeof( *ctxt ) ); + JNIEnv* env = *envp; + ctxt->envp = envp; + ctxt->jjniutil = (*env)->NewGlobalRef( env, jniutls ); + MPASSIGN( ctxt->mpool, mpool ); + return ctxt; +} + +void +destroyJNIUtil( JNIUtilCtxt** ctxtp ) +{ + JNIUtilCtxt* ctxt = *ctxtp; + if ( !!ctxt ) { + JNIEnv* env = *ctxt->envp; + (*env)->DeleteGlobalRef( env, ctxt->jjniutil ); + XP_FREE( ctxt->mpool, ctxt ); + *ctxtp = NULL; + } +} + +/* These are called from anddict.c, not via vtable */ +jobject +and_util_makeJBitmap( JNIUtilCtxt* jniutil, int nCols, int nRows, + const jboolean* colors ) +{ + jobject bitmap; + JNIEnv* env = *jniutil->envp; + jmethodID mid + = getMethodID( env, jniutil->jjniutil, "makeBitmap", + "(II[Z)Landroid/graphics/drawable/BitmapDrawable;" ); + + jbooleanArray jcolors = makeBooleanArray( env, nCols*nRows, colors ); + + bitmap = (*env)->CallObjectMethod( env, jniutil->jjniutil, mid, + nCols, nRows, jcolors ); + (*env)->DeleteLocalRef( env, jcolors ); + + return bitmap; +} + +jobject +and_util_splitFaces( JNIUtilCtxt* jniutil, const XP_U8* bytes, jsize len ) +{ + jobject strarray = NULL; + JNIEnv* env = *jniutil->envp; + jmethodID mid + = getMethodID( env, jniutil->jjniutil, "splitFaces", + "([B)[Ljava/lang/String;" ); + + jbyteArray jbytes = (*env)->NewByteArray( env, len ); + + jbyte* jp = (*env)->GetByteArrayElements( env, jbytes, NULL ); + XP_MEMCPY( jp, bytes, len ); + (*env)->ReleaseByteArrayElements( env, jbytes, jp, 0 ); + + strarray = (*env)->CallObjectMethod( env, jniutil->jjniutil, mid, jbytes ); + (*env)->DeleteLocalRef( env, jbytes ); + return strarray; +} diff --git a/xwords4/android/XWords4/jni/jniutlswrapper.h b/xwords4/android/XWords4/jni/jniutlswrapper.h new file mode 100644 index 000000000..83f8776f2 --- /dev/null +++ b/xwords4/android/XWords4/jni/jniutlswrapper.h @@ -0,0 +1,38 @@ +/* -*-mode: C; fill-column: 76; c-basic-offset: 4; -*- */ +/* + * Copyright 2001-2010 by Eric House (xwords@eehouse.org). All rights + * reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _JNIUTLSWRAPPER_H_ +#define _JNIUTLSWRAPPER_H_ + +#include + +#include "util.h" +#include "andglobals.h" + +typedef struct JNIUtilCtxt JNIUtilCtxt; + +JNIUtilCtxt* makeJNIUtil( MPFORMAL JNIEnv** env, jobject jniutls ); +void destroyJNIUtil( JNIUtilCtxt** jniu ); + +jobject and_util_makeJBitmap( JNIUtilCtxt* jniu, int nCols, int nRows, + const jboolean* colors ); +jobject and_util_splitFaces( JNIUtilCtxt* jniu, const XP_U8* bytes, int len ); + +#endif diff --git a/xwords4/android/XWords4/jni/utilwrapper.c b/xwords4/android/XWords4/jni/utilwrapper.c index 744600a62..c4de5b079 100644 --- a/xwords4/android/XWords4/jni/utilwrapper.c +++ b/xwords4/android/XWords4/jni/utilwrapper.c @@ -287,13 +287,11 @@ and_util_getUserString( XW_UtilCtxt* uc, XP_U16 stringCode ) const char* jchars = (*env)->GetStringUTFChars( env, jresult, NULL ); XP_MEMCPY( buf, jchars, len ); buf[len] = '\0'; - XP_LOGF( "got string from java: %s", buf ); (*env)->ReleaseStringUTFChars( env, jresult, jchars ); (*env)->DeleteLocalRef( env, jresult ); util->userStrings[index] = buf; } - LOG_RETURNF( "%s", util->userStrings[index] ); result = util->userStrings[index]; UTIL_CBK_TAIL(); return result; @@ -350,42 +348,6 @@ and_util_engineStopping( XW_UtilCtxt* uc ) } #endif -/* These are called from anddict.c, not via vtable */ -jobject -and_util_makeJBitmap( XW_UtilCtxt* uc, int nCols, int nRows, - const jboolean* colors ) -{ - jobject bitmap; - UTIL_CBK_HEADER( "makeBitmap", - "(II[Z)Landroid/graphics/drawable/BitmapDrawable;" ); - jbooleanArray jcolors = makeBooleanArray( env, nCols*nRows, colors ); - - bitmap = (*env)->CallObjectMethod( env, util->jutil, mid, - nCols, nRows, jcolors ); - (*env)->DeleteLocalRef( env, jcolors ); - UTIL_CBK_TAIL(); - return bitmap; -} - -jobject -and_util_splitFaces( XW_UtilCtxt* uc, const XP_U8* bytes, jsize len ) -{ - jobject strarray; - UTIL_CBK_HEADER( "splitFaces", "([B)[Ljava/lang/String;" ); - - jbyteArray jbytes = (*env)->NewByteArray( env, len ); - - jbyte* jp = (*env)->GetByteArrayElements( env, jbytes, NULL ); - XP_MEMCPY( jp, bytes, len ); - (*env)->ReleaseByteArrayElements( env, jbytes, jp, 0 ); - - strarray = (*env)->CallObjectMethod( env, util->jutil, mid, jbytes ); - (*env)->DeleteLocalRef( env, jbytes ); - UTIL_CBK_TAIL(); - return strarray; -} - - XW_UtilCtxt* makeUtil( MPFORMAL JNIEnv** envp, jobject jutil, CurGameInfo* gi, AndGlobals* closure ) @@ -447,7 +409,6 @@ makeUtil( MPFORMAL JNIEnv** envp, jobject jutil, CurGameInfo* gi, void destroyUtil( XW_UtilCtxt** utilc ) { - LOG_FUNC(); AndUtil* util = (AndUtil*)*utilc; JNIEnv *env = *util->env; @@ -465,5 +426,4 @@ destroyUtil( XW_UtilCtxt** utilc ) XP_FREE( util->util.mpool, util->util.vtable ); XP_FREE( util->util.mpool, util ); *utilc = NULL; - LOG_RETURN_VOID(); } diff --git a/xwords4/android/XWords4/jni/utilwrapper.h b/xwords4/android/XWords4/jni/utilwrapper.h index cb22c532b..f8f20b778 100644 --- a/xwords4/android/XWords4/jni/utilwrapper.h +++ b/xwords4/android/XWords4/jni/utilwrapper.h @@ -33,8 +33,4 @@ void destroyUtil( XW_UtilCtxt** util ); bool utilTimerFired( XW_UtilCtxt* util, XWTimerReason why, int handle ); -jobject and_util_makeJBitmap( XW_UtilCtxt* util, int nCols, int nRows, - const jboolean* colors ); -jobject and_util_splitFaces( XW_UtilCtxt* uc, const XP_U8* bytes, int len ); - #endif diff --git a/xwords4/android/XWords4/jni/xportwrapper.c b/xwords4/android/XWords4/jni/xportwrapper.c index f531e01e9..ee5bedeba 100644 --- a/xwords4/android/XWords4/jni/xportwrapper.c +++ b/xwords4/android/XWords4/jni/xportwrapper.c @@ -102,8 +102,6 @@ makeXportProcs( MPFORMAL JNIEnv** envp, jobject jxport ) { AndTransportProcs* aprocs = NULL; - XP_LOGF( "%s: jxport=%p", __func__, jxport ); - JNIEnv* env = *envp; aprocs = (AndTransportProcs*)XP_CALLOC( mpool, sizeof(*aprocs) ); if ( NULL != jxport ) { @@ -119,7 +117,6 @@ makeXportProcs( MPFORMAL JNIEnv** envp, jobject jxport ) aprocs->tp.rerror = and_xport_relayError; aprocs->tp.closure = aprocs; - LOG_RETURNF( "%p", aprocs ); return (TransportProcs*)aprocs; } diff --git a/xwords4/android/XWords4/jni/xwjni.c b/xwords4/android/XWords4/jni/xwjni.c index 43a65ebe2..55362da5a 100644 --- a/xwords4/android/XWords4/jni/xwjni.c +++ b/xwords4/android/XWords4/jni/xwjni.c @@ -16,6 +16,7 @@ #include "xportwrapper.h" #include "anddict.h" #include "andutils.h" +#include "jniutlswrapper.h" static CurGameInfo* makeGI( MPFORMAL JNIEnv* env, jobject j_gi ) @@ -219,6 +220,32 @@ Java_org_eehouse_android_xw4_jni_XwJNI_comms_1getInitialAddr setJAddrRec( env, jaddr, &addr ); } +/* Dictionary methods: don't use gamePtr */ +JNIEXPORT jboolean JNICALL +Java_org_eehouse_android_xw4_jni_XwJNI_dict_1tilesAreSame +( JNIEnv* env, jclass C, jint dictPtr1, jint dictPtr2 ) +{ + LOG_FUNC(); + jboolean result; + const DictionaryCtxt* dict1 = (DictionaryCtxt*)dictPtr1; + const DictionaryCtxt* dict2 = (DictionaryCtxt*)dictPtr2; + result = dict_tilesAreSame( dict1, dict2 ); + LOG_RETURNF( "%d", result ); + return result; +} + +JNIEXPORT jobjectArray JNICALL +Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getChars +( JNIEnv* env, jclass C, jint dictPtr ) +{ + LOG_FUNC(); + jobject result = NULL; + result = and_dictionary_getChars( env, (DictionaryCtxt*)dictPtr ); + (*env)->DeleteLocalRef( env, result ); + LOG_RETURNF( "%p", result ); + return result; +} + typedef struct _JNIState { XWGame game; JNIEnv* env; @@ -262,15 +289,16 @@ Java_org_eehouse_android_xw4_jni_XwJNI_initJNI JNIEXPORT void JNICALL Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeNewGame -( JNIEnv* env, jclass C, jint gamePtr, jobject j_gi, jobject j_util, - jobject j_draw, jobject j_cp, jobject j_procs, jbyteArray jDictBytes ) +( JNIEnv* env, jclass C, jint gamePtr, jobject j_gi, jobject j_util, + jobject jniu, jobject j_draw, jobject j_cp, jobject j_procs, + jbyteArray jDictBytes ) { XWJNI_START(); CurGameInfo* gi = makeGI( MPPARM(mpool) env, j_gi ); globals->gi = gi; - XW_UtilCtxt* util = makeUtil( MPPARM(mpool) &state->env, j_util, gi, - globals ); - globals->util = util; + globals->util = makeUtil( MPPARM(mpool) &state->env, j_util, gi, + globals ); + globals->jniutil = makeJNIUtil( MPPARM(mpool) &state->env, jniu ); DrawCtx* dctx = makeDraw( MPPARM(mpool) &state->env, j_draw ); globals->dctx = dctx; globals->xportProcs = makeXportProcs( MPPARM(mpool) &state->env, j_procs ); @@ -278,10 +306,11 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeNewGame loadCommonPrefs( env, &cp, j_cp ); XP_LOGF( "calling game_makeNewGame" ); - game_makeNewGame( MPPARM(mpool) &state->game, gi, util, dctx, &cp, + game_makeNewGame( MPPARM(mpool) &state->game, gi, globals->util, dctx, &cp, globals->xportProcs ); - DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, util, jDictBytes ); + DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, globals->jniutil, + jDictBytes ); #ifdef STUBBED_DICT if ( !dict ) { XP_LOGF( "falling back to stubbed dict" ); @@ -312,6 +341,7 @@ JNIEXPORT void JNICALL Java_org_eehouse_android_xw4_jni_XwJNI_game_1dispose destroyDraw( &globals->dctx ); destroyXportProcs( &globals->xportProcs ); destroyUtil( &globals->util ); + destroyJNIUtil( &globals->jniutil ); vtmgr_destroy( MPPARM(mpool) globals->vtMgr ); state->env = oldEnv; @@ -323,8 +353,8 @@ JNIEXPORT void JNICALL Java_org_eehouse_android_xw4_jni_XwJNI_game_1dispose JNIEXPORT jboolean JNICALL Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeFromStream ( JNIEnv* env, jclass C, jint gamePtr, jbyteArray jstream, - jobject /*out*/jgi, jbyteArray jdict, jobject jutil, jobject jdraw, - jobject jcp, jobject jprocs ) + jobject /*out*/jgi, jbyteArray jdict, jobject jutil, jobject jniu, + jobject jdraw, jobject jcp, jobject jprocs ) { jboolean result; XWJNI_START(); @@ -332,7 +362,8 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeFromStream globals->gi = (CurGameInfo*)XP_CALLOC( mpool, sizeof(*globals->gi) ); globals->util = makeUtil( MPPARM(mpool) &state->env, jutil, globals->gi, globals ); - DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, globals->util, jdict ); + globals->jniutil = makeJNIUtil( MPPARM(mpool) &state->env, jniu ); + DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, globals->jniutil, jdict ); globals->dctx = makeDraw( MPPARM(mpool) &state->env, jdraw ); globals->xportProcs = makeXportProcs( MPPARM(mpool) &state->env, jprocs ); @@ -357,6 +388,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeFromStream dict_destroy( dict ); dict = NULL; destroyUtil( &globals->util ); + destroyJNIUtil( &globals->jniutil ); destroyGI( MPPARM(mpool) &globals->gi ); } @@ -371,12 +403,19 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1saveToStream jbyteArray result; XWJNI_START(); - CurGameInfo* gi = makeGI( MPPARM(mpool) env, jgi ); + /* Use our copy of gi if none's provided. That's because only the caller + knows if its gi should win -- user has changed game config -- or if + ours should -- changes like remote players being added. */ + CurGameInfo* gi = + (NULL == jgi) ? globals->gi : makeGI( MPPARM(mpool) env, jgi ); XWStreamCtxt* stream = mem_stream_make( MPPARM(mpool) globals->vtMgr, NULL, 0, NULL ); game_saveToStream( &state->game, gi, stream ); - destroyGI( MPPARM(mpool) &gi ); + + if ( NULL != jgi ) { + destroyGI( MPPARM(mpool) &gi ); + } int nBytes = stream_getSize( stream ); result = (*env)->NewByteArray( env, nBytes ); diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java index a11b686f5..df731a3d8 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant reinstall"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ package org.eehouse.android.xw4; @@ -9,12 +9,10 @@ import android.view.MenuItem; import android.view.MenuInflater; import android.content.res.AssetManager; import java.io.InputStream; -import java.io.InputStreamReader; import android.os.Handler; import android.os.Message; import java.io.FileOutputStream; import java.io.FileInputStream; -import java.io.ByteArrayInputStream; import android.content.res.Configuration; import android.content.Intent; import java.util.concurrent.Semaphore; @@ -22,9 +20,6 @@ import android.net.Uri; import android.app.Dialog; import android.app.AlertDialog; import android.content.DialogInterface; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.Bitmap; -import java.util.ArrayList; import android.content.res.Resources; import org.eehouse.android.xw4.jni.*; @@ -51,6 +46,7 @@ public class BoardActivity extends Activity implements UtilCtxt { private int m_dlgTitle; private boolean m_dlgResult; private CommonPrefs m_cp; + private JNIUtils m_jniu; // call startActivityForResult synchronously private Semaphore m_forResultWait = new Semaphore(0); @@ -113,6 +109,7 @@ public class BoardActivity extends Activity implements UtilCtxt { super.onCreate( savedInstanceState ); m_cp = CommonPrefs.get(); + m_jniu = JNIUtilsImpl.get(); setContentView( R.layout.board ); m_handler = new Handler(); @@ -147,9 +144,9 @@ public class BoardActivity extends Activity implements UtilCtxt { if ( null == stream || ! XwJNI.game_makeFromStream( m_jniGamePtr, stream, m_gi, dictBytes, this, - m_view, m_cp, m_xport ) ) { - XwJNI.game_makeNewGame( m_jniGamePtr, m_gi, this, m_view, - m_cp, m_xport, dictBytes ); + m_jniu, m_view, m_cp, m_xport ) ) { + XwJNI.game_makeNewGame( m_jniGamePtr, m_gi, this, m_jniu, + m_view, m_cp, m_xport, dictBytes ); } m_jniThread = new @@ -193,7 +190,7 @@ public class BoardActivity extends Activity implements UtilCtxt { protected void onDestroy() { - byte[] state = XwJNI.game_saveToStream( m_jniGamePtr, m_gi ); + byte[] state = XwJNI.game_saveToStream( m_jniGamePtr, null ); Utils.saveGame( this, state, m_path ); if ( null != m_xport ) { @@ -596,63 +593,4 @@ public class BoardActivity extends Activity implements UtilCtxt { m_jniThread.handle( JNIThread.JNICmd.CMD_POST_OVER, R.string.finalscores_title ); } - - public BitmapDrawable makeBitmap( int width, int height, boolean[] colors ) - { - Bitmap bitmap = Bitmap.createBitmap( width, height, - Bitmap.Config.ARGB_8888 ); - - int indx = 0; - for ( int yy = 0; yy < height; ++yy ) { - for ( int xx = 0; xx < width; ++xx ) { - boolean pixelSet = colors[indx++]; - bitmap.setPixel( xx, yy, pixelSet? 0xFF000000 : 0x00FFFFFF ); - } - } - - // Doesn't compile if pass getResources(). Maybe the - // "deprecated" API is really the only one? - return new BitmapDrawable( /*getResources(), */bitmap ); - } - - /** Working around lack of utf8 support on the JNI side: given a - * utf-8 string with embedded small number vals starting with 0, - * convert into individual strings. The 0 is the problem: it's - * not valid utf8. So turn it and the other nums into strings and - * catch them on the other side. - */ - public String[] splitFaces( byte[] chars ) - { - ArrayList al = new ArrayList(); - int ii = 0; - ByteArrayInputStream bais = new ByteArrayInputStream( chars ); - InputStreamReader isr = new InputStreamReader( bais ); - - int[] codePoints = new int[1]; - - for ( ; ; ) { - int chr = -1; - try { - chr = isr.read(); - } catch ( java.io.IOException ioe ) { - Utils.logf( ioe.toString() ); - } - if ( -1 == chr ) { - break; - } else { - String letter; - if ( chr < 32 ) { - letter = String.format( "%d", chr ); - } else { - codePoints[0] = chr; - letter = new String( codePoints, 0, 1 ); - } - al.add( letter ); - } - } - - String[] result = al.toArray( new String[al.size()] ); - return result; - } - } // class BoardActivity diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardView.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardView.java index 89066cd0e..a858aca8c 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardView.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardView.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant reinstall"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ package org.eehouse.android.xw4; @@ -37,6 +37,7 @@ public class BoardView extends View implements DrawCtx, private String[] m_scores; private Rect m_boundsScratch; private String m_remText; + private int m_dictPtr = 0; private static final int BLACK = 0xFF000000; private static final int WHITE = 0xFFFFFFFF; @@ -359,6 +360,22 @@ public class BoardView extends View implements DrawCtx, } } + public void dictChanged( int dictPtr ) + { + Utils.logf( "BoardView::dictChanged" ); + if ( m_dictPtr != dictPtr ) { + if ( m_dictPtr == 0 || !XwJNI.dict_tilesAreSame( m_dictPtr, dictPtr ) ) { + String[] chars = XwJNI.dict_getChars( dictPtr ); + for ( String str : chars ) { + if ( str.length() > 0 && str.charAt(0) >= 32 ) { + Utils.logf( "got " + str ); + } + } + } + m_dictPtr = dictPtr; + } + } + private void drawTileImpl( Rect rect, String text, BitmapDrawable[] bitmaps, int val, int flags, boolean clearBack ) diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameConfig.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameConfig.java index 72937c977..a4a1ca3d0 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameConfig.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameConfig.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant reinstall"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ /* * Copyright (C) 2007 The Android Open Source Project @@ -241,9 +241,10 @@ public class GameConfig extends Activity implements View.OnClickListener { byte[] dictBytes = Utils.openDict( this, m_gi.dictName ); int gamePtr = XwJNI.initJNI(); - if ( !XwJNI.game_makeFromStream( gamePtr, stream, m_gi, dictBytes, - m_cp ) ) { - XwJNI.game_makeNewGame( gamePtr, m_gi, m_cp, dictBytes ); + if ( !XwJNI.game_makeFromStream( gamePtr, stream, JNIUtilsImpl.get(), + m_gi, dictBytes, m_cp ) ) { + XwJNI.game_makeNewGame( gamePtr, m_gi, JNIUtilsImpl.get(), + m_cp, dictBytes ); } int curSel = listAvailableDicts( m_gi.dictName ); @@ -616,7 +617,8 @@ public class GameConfig extends Activity implements View.OnClickListener { byte[] dictBytes = Utils.openDict( this, m_gi.dictName ); int gamePtr = XwJNI.initJNI(); - XwJNI.game_makeNewGame( gamePtr, m_gi, m_cp, dictBytes ); + XwJNI.game_makeNewGame( gamePtr, m_gi, JNIUtilsImpl.get(), + m_cp, dictBytes ); if ( null != m_car ) { XwJNI.comms_setAddr( gamePtr, m_car ); diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CommonPrefs.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CommonPrefs.java index 187802100..648255436 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CommonPrefs.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CommonPrefs.java @@ -77,7 +77,11 @@ public class CommonPrefs { { String key = s_context.getString( id ); String val = sp.getString( key, "" ); - return 0xFF000000 | Integer.decode( val ); + try { + return 0xFF000000 | Integer.decode( val ); + } catch ( java.lang.NumberFormatException nfe ) { + return 0xFF7F7F7F; + } } /* diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/DrawCtx.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/DrawCtx.java index 7fd3b4948..5d455ead4 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/DrawCtx.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/DrawCtx.java @@ -47,4 +47,6 @@ public interface DrawCtx { void objFinished( /*BoardObjectType*/int typ, Rect rect, int dfs ); + void dictChanged( int dictPtr ); + } diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java index 0c6f5efa1..2198a5fcb 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java @@ -61,7 +61,6 @@ public class JNIThread extends Thread { } public JNIThread( int gamePtr, CurGameInfo gi, Handler handler ) { - Utils.logf( "in JNIThread()" ); m_jniGamePtr = gamePtr; m_gi = gi; m_handler = handler; diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtils.java new file mode 100644 index 000000000..63cd12286 --- /dev/null +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtils.java @@ -0,0 +1,12 @@ +/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */ + +package org.eehouse.android.xw4.jni; + +import android.graphics.drawable.BitmapDrawable; + +public interface JNIUtils { + + // Stuff I can't do in C.... + BitmapDrawable makeBitmap( int width, int height, boolean[] colors ); + String[] splitFaces( byte[] chars ); +} \ No newline at end of file diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtilsImpl.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtilsImpl.java new file mode 100644 index 000000000..5f8094617 --- /dev/null +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtilsImpl.java @@ -0,0 +1,84 @@ +/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */ + +package org.eehouse.android.xw4.jni; + +import android.graphics.drawable.BitmapDrawable; +import android.graphics.Bitmap; +import java.util.ArrayList; +import java.io.ByteArrayInputStream; +import java.io.InputStreamReader; + +import org.eehouse.android.xw4.*; + +public class JNIUtilsImpl implements JNIUtils { + + private static JNIUtils s_impl = null; + + private JNIUtilsImpl(){} + + public static JNIUtils get() + { + if ( null == s_impl ) { + s_impl = new JNIUtilsImpl(); + } + return s_impl; + } + + public BitmapDrawable makeBitmap( int width, int height, boolean[] colors ) + { + Bitmap bitmap = Bitmap.createBitmap( width, height, + Bitmap.Config.ARGB_8888 ); + + int indx = 0; + for ( int yy = 0; yy < height; ++yy ) { + for ( int xx = 0; xx < width; ++xx ) { + boolean pixelSet = colors[indx++]; + bitmap.setPixel( xx, yy, pixelSet? 0xFF000000 : 0x00FFFFFF ); + } + } + + // Doesn't compile if pass getResources(). Maybe the + // "deprecated" API is really the only one? + return new BitmapDrawable( /*getResources(), */bitmap ); + } + + /** Working around lack of utf8 support on the JNI side: given a + * utf-8 string with embedded small number vals starting with 0, + * convert into individual strings. The 0 is the problem: it's + * not valid utf8. So turn it and the other nums into strings and + * catch them on the other side. + */ + public String[] splitFaces( byte[] chars ) + { + ArrayList al = new ArrayList(); + int ii = 0; + ByteArrayInputStream bais = new ByteArrayInputStream( chars ); + InputStreamReader isr = new InputStreamReader( bais ); + + int[] codePoints = new int[1]; + + for ( ; ; ) { + int chr = -1; + try { + chr = isr.read(); + } catch ( java.io.IOException ioe ) { + Utils.logf( ioe.toString() ); + } + if ( -1 == chr ) { + break; + } else { + String letter; + if ( chr < 32 ) { + letter = String.format( "%d", chr ); + } else { + codePoints[0] = chr; + letter = new String( codePoints, 0, 1 ); + } + al.add( letter ); + } + } + + String[] result = al.toArray( new String[al.size()] ); + return result; + } +} \ No newline at end of file diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/UtilCtxt.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/UtilCtxt.java index 6c6ce749a..3287c235d 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/UtilCtxt.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/UtilCtxt.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../../; ant reinstall"; -*- */ +/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */ package org.eehouse.android.xw4.jni; @@ -81,12 +81,6 @@ public interface UtilCtxt { void userError( int id ); void notifyGameOver(); - - BitmapDrawable makeBitmap( int width, int height, boolean[] colors ); - - String[] splitFaces( byte[] chars ); - // Don't need this unless we have a scroll thumb to indicate position //void yOffsetChange( int oldOffset, int newOffset ); - } diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/XwJNI.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/XwJNI.java index a3a6b741e..eb9932328 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/XwJNI.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/XwJNI.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../../; ant reinstall"; -*- */ +/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */ package org.eehouse.android.xw4.jni; @@ -28,6 +28,7 @@ public class XwJNI { public static native void game_makeNewGame( int gamePtr, CurGameInfo gi, UtilCtxt util, + JNIUtils jniu, DrawCtx draw, CommonPrefs cp, TransportProcs procs, byte[] dict ); @@ -37,25 +38,29 @@ public class XwJNI { CurGameInfo gi, byte[] dict, UtilCtxt util, + JNIUtils jniu, DrawCtx draw, CommonPrefs cp, TransportProcs procs ); // leave out options params for when game won't be rendered or // played - public static void game_makeNewGame( int gamePtr, CurGameInfo gi, - CommonPrefs cp, byte[] dict ) { - game_makeNewGame( gamePtr, gi, (UtilCtxt)null, + public static void game_makeNewGame( int gamePtr, CurGameInfo gi, + JNIUtils jniu, CommonPrefs cp, + byte[] dict ) { + game_makeNewGame( gamePtr, gi, (UtilCtxt)null, jniu, (DrawCtx)null, cp, (TransportProcs)null, dict ); } public static boolean game_makeFromStream( int gamePtr, byte[] stream, + JNIUtils jniu, CurGameInfo gi, byte[] dict, CommonPrefs cp ) { return game_makeFromStream( gamePtr, stream, gi, dict, (UtilCtxt)null, - (DrawCtx)null, cp, (TransportProcs)null ); + jniu, (DrawCtx)null, cp, + (TransportProcs)null ); } public static native boolean game_receiveMessage( int gamePtr, @@ -119,4 +124,8 @@ public class XwJNI { public static native void comms_start( int gamePtr ); public static native void comms_getAddr( int gamePtr, CommsAddrRec addr ); public static native void comms_setAddr( int gamePtr, CommsAddrRec addr ); + + // Dicts + public static native boolean dict_tilesAreSame( int dictPtr1, int dictPtr2 ); + public static native String[] dict_getChars( int dictPtr ); } diff --git a/xwords4/common/dictnry.h b/xwords4/common/dictnry.h index 5bacd1a81..e2bbc8d01 100644 --- a/xwords4/common/dictnry.h +++ b/xwords4/common/dictnry.h @@ -73,7 +73,7 @@ struct DictionaryCtxt { necessarily the entry point for search!! */ XP_UCHAR* name; XP_UCHAR* faces; - XP_UCHAR** facePtrs; + const XP_UCHAR** facePtrs; XP_U8* countsAndValues; SpecialBitmaps* bitmaps;