mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-02-12 08:47:50 +01:00
use smsproto in Android
This commit is contained in:
parent
2e9fbb8204
commit
3437ae2ebc
4 changed files with 157 additions and 156 deletions
|
@ -1,6 +1,6 @@
|
||||||
/* -*- compile-command: "find-and-gradle.sh insXw4Deb"; -*- */
|
/* -*- compile-command: "find-and-gradle.sh inXw4Deb"; -*- */
|
||||||
/*
|
/*
|
||||||
* Copyright 2010 by Eric House (xwords@eehouse.org). All rights
|
* Copyright 2010 - 2018 by Eric House (xwords@eehouse.org). All rights
|
||||||
* reserved.
|
* reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
|
@ -40,6 +40,7 @@ import org.eehouse.android.xw4.MultiService.DictFetchOwner;
|
||||||
import org.eehouse.android.xw4.MultiService.MultiEvent;
|
import org.eehouse.android.xw4.MultiService.MultiEvent;
|
||||||
import org.eehouse.android.xw4.jni.CommsAddrRec;
|
import org.eehouse.android.xw4.jni.CommsAddrRec;
|
||||||
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
|
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
|
||||||
|
import org.eehouse.android.xw4.jni.XwJNI;
|
||||||
import org.eehouse.android.xw4.loc.LocUtils;
|
import org.eehouse.android.xw4.loc.LocUtils;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
@ -55,19 +56,11 @@ import java.util.Set;
|
||||||
public class SMSService extends XWService {
|
public class SMSService extends XWService {
|
||||||
private static final String TAG = SMSService.class.getSimpleName();
|
private static final String TAG = SMSService.class.getSimpleName();
|
||||||
|
|
||||||
private static final String INSTALL_URL = "http://eehouse.org/_/a.py/a ";
|
|
||||||
private static final int MAX_SMS_LEN = 140; // ??? differs by network
|
|
||||||
private static final int KITKAT = 19;
|
|
||||||
|
|
||||||
private static final String MSG_SENT = "MSG_SENT";
|
private static final String MSG_SENT = "MSG_SENT";
|
||||||
private static final String MSG_DELIVERED = "MSG_DELIVERED";
|
private static final String MSG_DELIVERED = "MSG_DELIVERED";
|
||||||
|
|
||||||
private static final int SMS_PROTO_VERSION_ORIG = 0;
|
|
||||||
private static final int SMS_PROTO_VERSION_WITHPORT = 1;
|
private static final int SMS_PROTO_VERSION_WITHPORT = 1;
|
||||||
private static final int SMS_PROTO_VERSION = SMS_PROTO_VERSION_WITHPORT;
|
private static final int SMS_PROTO_VERSION = SMS_PROTO_VERSION_WITHPORT;
|
||||||
private static final int MAX_LEN_TEXT = 100;
|
|
||||||
private static final int MAX_LEN_BINARY = 100;
|
|
||||||
private static final int MAX_MSG_COUNT = 16; // 1.6K enough? Should be....
|
|
||||||
private enum SMSAction { _NONE,
|
private enum SMSAction { _NONE,
|
||||||
INVITE,
|
INVITE,
|
||||||
SEND,
|
SEND,
|
||||||
|
@ -75,6 +68,7 @@ public class SMSService extends XWService {
|
||||||
ADDED_MISSING,
|
ADDED_MISSING,
|
||||||
STOP_SELF,
|
STOP_SELF,
|
||||||
HANDLEDATA,
|
HANDLEDATA,
|
||||||
|
RESEND,
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final String CMD_STR = "CMD";
|
private static final String CMD_STR = "CMD";
|
||||||
|
@ -98,8 +92,6 @@ public class SMSService extends XWService {
|
||||||
|
|
||||||
private int m_nReceived = 0;
|
private int m_nReceived = 0;
|
||||||
private static int s_nSent = 0;
|
private static int s_nSent = 0;
|
||||||
private static Map<String, HashMap <Integer, MsgStore>> s_partialMsgs
|
|
||||||
= new HashMap<String, HashMap <Integer, MsgStore>>();
|
|
||||||
private static Set<Integer> s_sentDied = new HashSet<Integer>();
|
private static Set<Integer> s_sentDied = new HashSet<Integer>();
|
||||||
|
|
||||||
public static class SMSPhoneInfo {
|
public static class SMSPhoneInfo {
|
||||||
|
@ -366,6 +358,9 @@ public class SMSService extends XWService {
|
||||||
phone = intent.getStringExtra( PHONE );
|
phone = intent.getStringExtra( PHONE );
|
||||||
sendDiedPacket( phone, gameID );
|
sendDiedPacket( phone, gameID );
|
||||||
break;
|
break;
|
||||||
|
case RESEND:
|
||||||
|
phone = intent.getStringExtra( PHONE );
|
||||||
|
resendFor( phone, null, false );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,16 +429,15 @@ public class SMSService extends XWService {
|
||||||
dos.writeInt( gameID );
|
dos.writeInt( gameID );
|
||||||
dos.write( bytes, 0, bytes.length );
|
dos.write( bytes, 0, bytes.length );
|
||||||
dos.flush();
|
dos.flush();
|
||||||
if ( send( SMS_CMD.DATA, bas.toByteArray(), phone ) ) {
|
send( SMS_CMD.DATA, bas.toByteArray(), phone );
|
||||||
nSent = bytes.length;
|
nSent = bytes.length;
|
||||||
}
|
|
||||||
} catch ( java.io.IOException ioe ) {
|
} catch ( java.io.IOException ioe ) {
|
||||||
Log.ex( TAG, ioe );
|
Log.ex( TAG, ioe );
|
||||||
}
|
}
|
||||||
return nSent;
|
return nSent;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean send( SMS_CMD cmd, byte[] bytes, String phone )
|
private void send( SMS_CMD cmd, byte[] bytes, String phone )
|
||||||
throws java.io.IOException
|
throws java.io.IOException
|
||||||
{
|
{
|
||||||
ByteArrayOutputStream bas = new ByteArrayOutputStream( 128 );
|
ByteArrayOutputStream bas = new ByteArrayOutputStream( 128 );
|
||||||
|
@ -457,42 +451,47 @@ public class SMSService extends XWService {
|
||||||
dos.flush();
|
dos.flush();
|
||||||
|
|
||||||
byte[] data = bas.toByteArray();
|
byte[] data = bas.toByteArray();
|
||||||
byte[][] msgs = breakAndEncode( data );
|
|
||||||
boolean result = null != msgs && sendBuffers( msgs, phone );
|
boolean forceNow = cmd == SMS_CMD.INVITE || cmd == SMS_CMD.DATA;
|
||||||
return result;
|
// forceNow should always be true on first release since old code
|
||||||
|
// can't do the combined-messages stuff. Let's assert so we change
|
||||||
|
// when close to release.
|
||||||
|
Assert.assertTrue( BuildConfig.DEBUG );
|
||||||
|
resendFor( phone, data, forceNow );
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[][] breakAndEncode( byte msg[] ) throws java.io.IOException
|
private void resendFor( String phone, byte[] data, boolean forceNow )
|
||||||
{
|
{
|
||||||
byte[][] result = null;
|
int[] waitSecs = { 0 };
|
||||||
int count = (msg.length + (MAX_LEN_BINARY-1)) / MAX_LEN_BINARY;
|
byte[][] msgs = XwJNI.smsproto_prepOutbound( data, phone, forceNow, waitSecs );
|
||||||
if ( count < MAX_MSG_COUNT ) {
|
if ( null != msgs ) {
|
||||||
result = new byte[count][];
|
sendBuffers( msgs, phone );
|
||||||
int msgID = ++s_nSent % 0x000000FF;
|
}
|
||||||
|
if ( waitSecs[0] > 0 ) {
|
||||||
|
Assert.assertFalse( forceNow );
|
||||||
|
postResend( phone, waitSecs[0] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int start = 0;
|
private void postResend( final String phone, final int waitSecs )
|
||||||
int end = 0;
|
{
|
||||||
for ( int ii = 0; ii < count; ++ii ) {
|
Log.d( TAG, "postResend" );
|
||||||
int len = msg.length - end;
|
new Thread(new Runnable() {
|
||||||
if ( len > MAX_LEN_BINARY ) {
|
@Override
|
||||||
len = MAX_LEN_BINARY;
|
public void run() {
|
||||||
}
|
try {
|
||||||
end += len;
|
Thread.sleep( waitSecs * 1000 );
|
||||||
byte[] part = new byte[4 + len];
|
|
||||||
part[0] = (byte)SMS_PROTO_VERSION;
|
|
||||||
part[1] = (byte)msgID;
|
|
||||||
part[2] = (byte)ii;
|
|
||||||
part[3] = (byte)count;
|
|
||||||
System.arraycopy( msg, start, part, 4, len );
|
|
||||||
|
|
||||||
result[ii] = part;
|
Log.d( TAG, "postResend.run()" );
|
||||||
start = end;
|
Intent intent = getIntentTo( SMSService.this,
|
||||||
|
SMSAction.RESEND );
|
||||||
|
intent.putExtra( PHONE, phone );
|
||||||
|
startService( intent );
|
||||||
|
} catch ( InterruptedException ie ) {
|
||||||
|
Log.e( TAG, ie.getMessage() );
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Log.w( TAG, "breakAndEncode(): msg count %d too large; dropping",
|
|
||||||
count );
|
|
||||||
}
|
}
|
||||||
return result;
|
} ).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void receive( SMS_CMD cmd, byte[] data, String phone )
|
private void receive( SMS_CMD cmd, byte[] data, String phone )
|
||||||
|
@ -534,53 +533,20 @@ public class SMSService extends XWService {
|
||||||
|
|
||||||
private void receiveBuffer( byte[] buffer, String senderPhone )
|
private void receiveBuffer( byte[] buffer, String senderPhone )
|
||||||
{
|
{
|
||||||
byte proto = buffer[0];
|
byte[][] msgs = XwJNI.smsproto_prepInbound( buffer, senderPhone );
|
||||||
int id = buffer[1];
|
if ( null != msgs ) {
|
||||||
int index = buffer[2];
|
for ( byte[] msg : msgs ) {
|
||||||
int count = buffer[3];
|
if ( !disAssemble( senderPhone, msg ) ) {
|
||||||
byte[] rest = new byte[buffer.length - 4];
|
Log.e( TAG, "failed on message from %s", senderPhone );
|
||||||
System.arraycopy( buffer, 4, rest, 0, rest.length );
|
}
|
||||||
if ( tryAssemble( senderPhone, id, index, count, rest ) ) {
|
}
|
||||||
postEvent( MultiEvent.SMS_RECEIVE_OK );
|
postEvent( MultiEvent.SMS_RECEIVE_OK );
|
||||||
} else {
|
} else {
|
||||||
// Will see this when don't have SMS permission
|
Log.w( TAG, "receiveBuffer(): bogus or incomplete message from phone %s",
|
||||||
Log.w( TAG, "receiveBuffer(): bogus message from phone %s",
|
|
||||||
senderPhone );
|
senderPhone );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean tryAssemble( String senderPhone, int id, int index,
|
|
||||||
int count, byte[] msg )
|
|
||||||
{
|
|
||||||
boolean success = true;
|
|
||||||
if ( index == 0 && count == 1 ) { // most common case
|
|
||||||
success = disAssemble( senderPhone, msg );
|
|
||||||
} else if ( count > 0 && count < MAX_MSG_COUNT && index < count ) {
|
|
||||||
// required? Should always be in main thread.
|
|
||||||
synchronized( s_partialMsgs ) {
|
|
||||||
HashMap<Integer, MsgStore> perPhone =
|
|
||||||
s_partialMsgs.get( senderPhone );
|
|
||||||
if ( null == perPhone ) {
|
|
||||||
perPhone = new HashMap <Integer, MsgStore>();
|
|
||||||
s_partialMsgs.put( senderPhone, perPhone );
|
|
||||||
}
|
|
||||||
MsgStore store = perPhone.get( id );
|
|
||||||
if ( null == store ) {
|
|
||||||
store = new MsgStore( id, count, false );
|
|
||||||
perPhone.put( id, store );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( store.add( index, msg ).isComplete() ) {
|
|
||||||
success = disAssemble( senderPhone, store.messageData() );
|
|
||||||
perPhone.remove( id );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean disAssemble( String senderPhone, byte[] fullMsg )
|
private boolean disAssemble( String senderPhone, byte[] fullMsg )
|
||||||
{
|
{
|
||||||
boolean success = false;
|
boolean success = false;
|
||||||
|
@ -685,7 +651,7 @@ public class SMSService extends XWService {
|
||||||
Log.i( TAG, "dropping because SMS disabled" );
|
Log.i( TAG, "dropping because SMS disabled" );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( showToasts( this ) && success && (0 == (s_nSent % 5)) ) {
|
if ( showToasts( this ) && success && (0 == (++s_nSent % 5)) ) {
|
||||||
DbgUtils.showf( this, "Sent msg %d", s_nSent );
|
DbgUtils.showf( this, "Sent msg %d", s_nSent );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -777,70 +743,4 @@ public class SMSService extends XWService {
|
||||||
return sendPacket( addr.sms_phone, gameID, buf );
|
return sendPacket( addr.sms_phone, gameID, buf );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MsgStore {
|
|
||||||
String[] m_msgsText;
|
|
||||||
byte[][] m_msgsData;
|
|
||||||
int m_msgID;
|
|
||||||
int m_haveCount;
|
|
||||||
int m_fullLength;
|
|
||||||
|
|
||||||
public MsgStore( int id, int count, boolean usingStrings )
|
|
||||||
{
|
|
||||||
m_msgID = id;
|
|
||||||
if ( usingStrings ) {
|
|
||||||
m_msgsText = new String[count];
|
|
||||||
} else {
|
|
||||||
m_msgsData = new byte[count][];
|
|
||||||
}
|
|
||||||
m_fullLength = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MsgStore add( int index, String msg )
|
|
||||||
{
|
|
||||||
if ( null == m_msgsText[index] ) {
|
|
||||||
++m_haveCount;
|
|
||||||
m_fullLength += msg.length();
|
|
||||||
}
|
|
||||||
m_msgsText[index] = msg;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MsgStore add( int index, byte[] msg )
|
|
||||||
{
|
|
||||||
if ( null == m_msgsData[index] ) {
|
|
||||||
++m_haveCount;
|
|
||||||
m_fullLength += msg.length;
|
|
||||||
}
|
|
||||||
m_msgsData[index] = msg;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isComplete()
|
|
||||||
{
|
|
||||||
int count = null != m_msgsText ? m_msgsText.length : m_msgsData.length;
|
|
||||||
boolean complete = count == m_haveCount;
|
|
||||||
return complete;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String messageText()
|
|
||||||
{
|
|
||||||
StringBuffer sb = new StringBuffer(m_fullLength);
|
|
||||||
for ( String msg : m_msgsText ) {
|
|
||||||
sb.append( msg );
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] messageData()
|
|
||||||
{
|
|
||||||
byte[] result = new byte[m_fullLength];
|
|
||||||
int indx = 0;
|
|
||||||
for ( byte[] msg : m_msgsData ) {
|
|
||||||
System.arraycopy( msg, 0, result, indx, msg.length );
|
|
||||||
indx += msg.length;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -403,6 +403,19 @@ public class XwJNI {
|
||||||
public static native boolean comms_getAddrDisabled( GamePtr gamePtr, CommsConnType typ,
|
public static native boolean comms_getAddrDisabled( GamePtr gamePtr, CommsConnType typ,
|
||||||
boolean send );
|
boolean send );
|
||||||
|
|
||||||
|
public static byte[][] smsproto_prepOutbound( byte[] buf, String phone, boolean forceNow,
|
||||||
|
/*out*/ int[] waitSecs )
|
||||||
|
{
|
||||||
|
int nowSeconds = (int)(System.currentTimeMillis() / 1000);
|
||||||
|
return smsproto_prepOutbound( getJNI().m_ptr, buf, phone, nowSeconds,
|
||||||
|
forceNow, waitSecs );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[][] smsproto_prepInbound( byte[] data, String fromPhone )
|
||||||
|
{
|
||||||
|
return smsproto_prepInbound( getJNI().m_ptr, data, fromPhone );
|
||||||
|
}
|
||||||
|
|
||||||
// Dicts
|
// Dicts
|
||||||
public static class DictWrapper {
|
public static class DictWrapper {
|
||||||
private int m_dictPtr;
|
private int m_dictPtr;
|
||||||
|
@ -489,5 +502,13 @@ public class XwJNI {
|
||||||
private static native int dict_iter_init( int jniState, byte[] dict,
|
private static native int dict_iter_init( int jniState, byte[] dict,
|
||||||
String name, String path );
|
String name, String path );
|
||||||
|
|
||||||
|
private static native byte[][] smsproto_prepOutbound( int jniState, byte[] buf,
|
||||||
|
String phone, int nowSeconds,
|
||||||
|
boolean forceNow,
|
||||||
|
/*out*/int[] waitSecs );
|
||||||
|
|
||||||
|
private static native byte[][] smsproto_prepInbound( int jniState, byte[] data,
|
||||||
|
String fromPhone );
|
||||||
|
|
||||||
private static native boolean haveEnv( int jniState );
|
private static native boolean haveEnv( int jniState );
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,6 +84,7 @@ COMMON_SRC_FILES += \
|
||||||
$(COMMON_PATH)/movestak.c \
|
$(COMMON_PATH)/movestak.c \
|
||||||
$(COMMON_PATH)/dbgutil.c \
|
$(COMMON_PATH)/dbgutil.c \
|
||||||
$(COMMON_PATH)/nli.c \
|
$(COMMON_PATH)/nli.c \
|
||||||
|
$(COMMON_PATH)/smsproto.c \
|
||||||
|
|
||||||
LOCAL_CFLAGS+=$(LOCAL_C_INCLUDES) $(LOCAL_DEFINES) -Wall -std=c99
|
LOCAL_CFLAGS+=$(LOCAL_C_INCLUDES) $(LOCAL_DEFINES) -Wall -std=c99
|
||||||
LOCAL_SRC_FILES := $(linux_SRC_FILES) $(LOCAL_SRC_FILES) $(COMMON_SRC_FILES)
|
LOCAL_SRC_FILES := $(linux_SRC_FILES) $(LOCAL_SRC_FILES) $(COMMON_SRC_FILES)
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "dictiter.h"
|
#include "dictiter.h"
|
||||||
#include "dictmgr.h"
|
#include "dictmgr.h"
|
||||||
#include "nli.h"
|
#include "nli.h"
|
||||||
|
#include "smsproto.h"
|
||||||
|
|
||||||
#include "utilwrapper.h"
|
#include "utilwrapper.h"
|
||||||
#include "drawwrapper.h"
|
#include "drawwrapper.h"
|
||||||
|
@ -60,6 +61,7 @@ struct _EnvThreadInfo {
|
||||||
typedef struct _JNIGlobalState {
|
typedef struct _JNIGlobalState {
|
||||||
EnvThreadInfo ti;
|
EnvThreadInfo ti;
|
||||||
DictMgrCtxt* dictMgr;
|
DictMgrCtxt* dictMgr;
|
||||||
|
SMSProto* smsProto;
|
||||||
VTableMgr* vtMgr;
|
VTableMgr* vtMgr;
|
||||||
XW_DUtilCtxt* dutil;
|
XW_DUtilCtxt* dutil;
|
||||||
JNIUtilCtxt* jniutil;
|
JNIUtilCtxt* jniutil;
|
||||||
|
@ -290,6 +292,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_initGlobals
|
||||||
state->dutil = makeDUtil( MPPARM(mpool) &state->ti, jdutil, state->vtMgr,
|
state->dutil = makeDUtil( MPPARM(mpool) &state->ti, jdutil, state->vtMgr,
|
||||||
state->jniutil, NULL );
|
state->jniutil, NULL );
|
||||||
state->dictMgr = dmgr_make( MPPARM_NOCOMMA( mpool ) );
|
state->dictMgr = dmgr_make( MPPARM_NOCOMMA( mpool ) );
|
||||||
|
state->smsProto = smsproto_init( MPPARM( mpool ) state->dutil );
|
||||||
MPASSIGN( state->mpool, mpool );
|
MPASSIGN( state->mpool, mpool );
|
||||||
// LOG_RETURNF( "%p", state );
|
// LOG_RETURNF( "%p", state );
|
||||||
return (jint)state;
|
return (jint)state;
|
||||||
|
@ -306,6 +309,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_cleanGlobals
|
||||||
MemPoolCtx* mpool = getMPool( state );
|
MemPoolCtx* mpool = getMPool( state );
|
||||||
#endif
|
#endif
|
||||||
XP_ASSERT( ENVFORME(&state->ti) == env );
|
XP_ASSERT( ENVFORME(&state->ti) == env );
|
||||||
|
smsproto_free( state->smsProto );
|
||||||
vtmgr_destroy( MPPARM(mpool) state->vtMgr );
|
vtmgr_destroy( MPPARM(mpool) state->vtMgr );
|
||||||
dmgr_destroy( state->dictMgr );
|
dmgr_destroy( state->dictMgr );
|
||||||
destroyDUtil( &state->dutil );
|
destroyDUtil( &state->dutil );
|
||||||
|
@ -761,6 +765,81 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getTileValue
|
||||||
return dict_getTileValue( (DictionaryCtxt*)dictPtr, tile );
|
return dict_getTileValue( (DictionaryCtxt*)dictPtr, tile );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static jobjectArray
|
||||||
|
msgArrayToByteArrays( JNIEnv* env, const SMSMsgArray* arr )
|
||||||
|
{
|
||||||
|
jclass clas = (*env)->FindClass( env, "[B" );
|
||||||
|
jobjectArray result = (*env)->NewObjectArray( env, arr->nMsgs, clas, NULL );
|
||||||
|
for ( int ii = 0; ii < arr->nMsgs; ++ii ) {
|
||||||
|
SMSMsg* msg = &arr->msgs[ii];
|
||||||
|
jbyteArray arr = makeByteArray( env, msg->len, (const jbyte*)msg->data );
|
||||||
|
(*env)->SetObjectArrayElement( env, result, ii, arr );
|
||||||
|
deleteLocalRef( env, arr );
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jobjectArray JNICALL
|
||||||
|
Java_org_eehouse_android_xw4_jni_XwJNI_smsproto_1prepOutbound
|
||||||
|
( JNIEnv* env, jclass C, jint jniGlobalPtr, jbyteArray jData,
|
||||||
|
jstring jToPhone, jint jNow, jboolean jForce, jintArray jWaitSecsArr )
|
||||||
|
{
|
||||||
|
jobjectArray result = NULL;
|
||||||
|
JNIGlobalState* state = (JNIGlobalState*)jniGlobalPtr;
|
||||||
|
map_thread( &state->ti, env );
|
||||||
|
|
||||||
|
jbyte* data = NULL;
|
||||||
|
int len = 0;
|
||||||
|
if ( NULL != jData ) {
|
||||||
|
len = (*env)->GetArrayLength( env, jData );
|
||||||
|
data = (*env)->GetByteArrayElements( env, jData, NULL );
|
||||||
|
}
|
||||||
|
const char* toPhone = (*env)->GetStringUTFChars( env, jToPhone, NULL );
|
||||||
|
|
||||||
|
XP_U16 waitSecs;
|
||||||
|
SMSMsgArray* arr = smsproto_prepOutbound( state->smsProto, (const XP_U8*)data,
|
||||||
|
len, toPhone, jForce, &waitSecs );
|
||||||
|
if ( !!arr ) {
|
||||||
|
result = msgArrayToByteArrays( env, arr );
|
||||||
|
smsproto_freeMsgArray( state->smsProto, arr );
|
||||||
|
}
|
||||||
|
|
||||||
|
setIntInArray( env, jWaitSecsArr, 0, waitSecs );
|
||||||
|
|
||||||
|
(*env)->ReleaseStringUTFChars( env, jToPhone, toPhone );
|
||||||
|
if ( NULL != jData ) {
|
||||||
|
(*env)->ReleaseByteArrayElements( env, jData, data, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jobjectArray JNICALL
|
||||||
|
Java_org_eehouse_android_xw4_jni_XwJNI_smsproto_1prepInbound
|
||||||
|
( JNIEnv* env, jclass C, jint jniGlobalPtr, jbyteArray jData,
|
||||||
|
jstring jFromPhone )
|
||||||
|
{
|
||||||
|
jobjectArray result = NULL;
|
||||||
|
JNIGlobalState* state = (JNIGlobalState*)jniGlobalPtr;
|
||||||
|
map_thread( &state->ti, env );
|
||||||
|
|
||||||
|
int len = (*env)->GetArrayLength( env, jData );
|
||||||
|
jbyte* data = (*env)->GetByteArrayElements( env, jData, NULL );
|
||||||
|
const char* fromPhone = (*env)->GetStringUTFChars( env, jFromPhone, NULL );
|
||||||
|
|
||||||
|
SMSMsgArray* arr = smsproto_prepInbound( state->smsProto, fromPhone,
|
||||||
|
(XP_U8*)data, len );
|
||||||
|
if ( !!arr ) {
|
||||||
|
result = msgArrayToByteArrays( env, arr );
|
||||||
|
smsproto_freeMsgArray( state->smsProto, arr );
|
||||||
|
}
|
||||||
|
|
||||||
|
(*env)->ReleaseStringUTFChars( env, jFromPhone, fromPhone );
|
||||||
|
(*env)->ReleaseByteArrayElements( env, jData, data, 0 );
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
struct _JNIState {
|
struct _JNIState {
|
||||||
XWGame game;
|
XWGame game;
|
||||||
JNIGlobalState* globalJNI;
|
JNIGlobalState* globalJNI;
|
||||||
|
|
Loading…
Add table
Reference in a new issue