flesh out MultiMsgSink so that subclasses invoked e.g. in response to

BT traffic can send messages via other means as well.  Relay games
with both participants on one device work again.
This commit is contained in:
Eric House 2014-11-19 18:46:35 -08:00
parent f14a1c095f
commit 1962371fe2
11 changed files with 146 additions and 101 deletions

View file

@ -1361,6 +1361,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1receiveMessage
jstream );
CommsAddrRec* addrp = NULL;
CommsAddrRec addr = {0};
XP_ASSERT( !!jaddr );
if ( NULL != jaddr ) {
getJAddrRec( env, &addr, jaddr );
addrp = &addr;

View file

@ -150,7 +150,7 @@ public class BTService extends XWService {
private BluetoothAdapter m_adapter;
private Set<String> m_addrs;
private MultiMsgSink m_btMsgSink;
private BTMsgSink m_btMsgSink;
private BTListenerThread m_listener;
private BTSenderThread m_sender;
private static int s_errCount = 0;
@ -1064,10 +1064,8 @@ public class BTService extends XWService {
BTCmd result;
long[] rowids = DBUtils.getRowIDsFor( BTService.this, nli.gameID );
if ( null == rowids || 0 == rowids.length ) {
CommsAddrRec addr = new CommsAddrRec( sender, senderAddress );
long rowid = GameUtils.makeNewGame( context, m_btMsgSink, nli.gameID,
addr, nli.lang, nli.dict, nli.nPlayersT,
nli.nPlayersH );
CommsAddrRec addr = nli.makeAddrRec( context );
long rowid = GameUtils.makeNewMultiGame( context, nli, m_btMsgSink );
if ( DBUtils.ROWID_NOTFOUND == rowid ) {
result = BTCmd.INVITE_FAILED;
} else {
@ -1171,20 +1169,15 @@ public class BTService extends XWService {
private class BTMsgSink extends MultiMsgSink {
/***** TransportProcs interface *****/
public BTMsgSink() { super( BTService.this ); }
public int transportSend( byte[] buf, final CommsAddrRec addr, int gameID )
@Override
public int sendViaBluetooth( byte[] buf, int gameID, CommsAddrRec addr )
{
int sent = -1;
if ( null != addr ) {
m_sender.add( new BTQueueElem( BTCmd.MESG_SEND, buf,
addr.bt_btAddr, gameID ) );
sent = buf.length;
} else {
DbgUtils.logf( "BTMsgSink.transportSend: "
+ "addr null so not sending" );
}
return sent;
Assert.assertTrue( addr.contains( CommsConnType.COMMS_CONN_BT ) );
m_sender.add( new BTQueueElem( BTCmd.MESG_SEND, buf,
addr.bt_btAddr, gameID ) );
return buf.length;
}
}

View file

@ -165,12 +165,14 @@ public class BoardDelegate extends DelegateBase
return delivered;
}
public static boolean feedMessage( long rowid, byte[] msg )
public static boolean feedMessage( long rowid, byte[] msg,
CommsAddrRec ret )
{
return feedMessages( rowid, new byte[][]{msg} );
return feedMessages( rowid, new byte[][]{msg}, ret );
}
public static boolean feedMessages( long rowid, byte[][] msgs )
public static boolean feedMessages( long rowid, byte[][] msgs,
CommsAddrRec ret )
{
boolean delivered = false;
Assert.assertNotNull( msgs );
@ -185,8 +187,7 @@ public class BoardDelegate extends DelegateBase
if ( rowid == self.m_rowid ) {
delivered = true; // even if no messages!
for ( byte[] msg : msgs ) {
self.m_jniThread.handle( JNICmd.CMD_RECEIVE, msg,
null );
self.m_jniThread.handle( JNICmd.CMD_RECEIVE, msg, ret );
}
}
}

View file

@ -371,7 +371,7 @@ public class CommsTransport implements TransportProcs,
}
if ( !XWApp.UDP_ENABLED
&& addr.conTypes.contains(CommsConnType.COMMS_CONN_RELAY) ) {
&& addr.contains(CommsConnType.COMMS_CONN_RELAY) ) {
if ( NetStateCache.netAvail( m_context ) ) {
putOut( buf ); // add to queue
if ( null == m_thread ) {
@ -434,9 +434,10 @@ public class CommsTransport implements TransportProcs,
return false;
}
public static int sendForAddr( Context context, CommsAddrRec addr,
long rowID, int gameID, byte[] buf )
private static int sendForAddr( Context context, CommsAddrRec addr,
long rowID, int gameID, byte[] buf )
{
DbgUtils.logf( "sendForAddr(addr=%s)", addr.conTypes.toString() );
int mostSent = -1;
for ( Iterator<CommsConnType> iter = addr.conTypes.iterator();
iter.hasNext(); ) {
@ -458,10 +459,12 @@ public class CommsTransport implements TransportProcs,
Assert.fail();
break;
}
if ( nSent < mostSent ) {
nSent = mostSent;
if ( mostSent < nSent ) {
mostSent = nSent;
}
}
DbgUtils.logf( "sendForAddr(addr=%s)=>%d", addr.conTypes.toString(),
mostSent );
return mostSent;
}

View file

@ -499,6 +499,9 @@ public class ConnStatusHandler {
result = XWApp.BTSUPPORTED && BTService.BTEnabled()
&& !getAirplaneModeOn( context );
break;
case COMMS_CONN_RELAY:
result = NetStateCache.netAvail( context );
break;
default:
DbgUtils.logf( "ConnStatusHandler:connTypeEnabled: %s not handled",
connType.toString() );

View file

@ -453,11 +453,17 @@ public class GameUtils {
}
public static long makeNewMultiGame( Context context, NetLaunchInfo nli )
{
return makeNewMultiGame( context, nli, null );
}
public static long makeNewMultiGame( Context context, NetLaunchInfo nli,
MultiMsgSink sink )
{
DbgUtils.logf( "makeNewMultiGame(nli=%s)", nli.toString() );
CommsAddrRec addr = nli.makeAddrRec( context );
return makeNewMultiGame( context, null, DBUtils.GROUPID_UNSPEC, addr,
return makeNewMultiGame( context, sink, DBUtils.GROUPID_UNSPEC, addr,
new int[] {nli.lang}, new String[] { nli.dict },
nli.nPlayersT, 1, nli.inviteID,
nli.gameID, false );
@ -509,6 +515,9 @@ public class GameUtils {
// work
Assert.assertTrue( gi.nPlayers == nPlayersT );
rowid = saveNew( context, gi, groupID );
if ( null != sink ) {
sink.setRowID( rowid );
}
if ( DBUtils.ROWID_NOTFOUND != rowid ) {
GameLock lock = new GameLock( rowid, true ).lock();
@ -1076,7 +1085,7 @@ public class GameUtils {
private HashMap<Long,CommsConnTypeSet> m_games;
private boolean m_showUI;
private CommsConnType m_filter;
private int m_nSent = 0;
private MultiMsgSink m_sink;
public ResendTask( Context context, HashMap<Long,CommsConnTypeSet> games,
CommsConnType filter, boolean showUI )
@ -1103,8 +1112,8 @@ public class GameUtils {
GameLock lock = new GameLock( rowid, false );
if ( lock.tryLock() ) {
CurGameInfo gi = new CurGameInfo( m_context );
MsgSink sink = new MsgSink( m_context, rowid );
int gamePtr = loadMakeGame( m_context, gi, sink, lock );
m_sink = new MultiMsgSink( m_context, rowid );
int gamePtr = loadMakeGame( m_context, gi, m_sink, lock );
if ( 0 != gamePtr ) {
XwJNI.comms_resendAll( gamePtr, true, false );
}
@ -1121,36 +1130,8 @@ public class GameUtils {
protected void onPostExecute( Void unused )
{
if ( m_showUI ) {
DbgUtils.showf( m_context, R.string.resend_finished_fmt, m_nSent );
}
}
private class MsgSink extends MultiMsgSink {
private Context m_context;
private long m_rowid;
public MsgSink( Context context, long rowid )
{
m_context = context;
m_rowid = rowid;
}
@Override
public boolean relayNoConnProc( byte[] buf, String relayID )
{
int len = buf.length;
if ( len == RelayService.sendNoConnPacket( m_context, m_rowid,
relayID, buf ) ) {
++m_nSent;
}
return true;
}
public int transportSend( byte[] buf, final CommsAddrRec addr, int gameID )
{
return null == addr ? -1
: CommsTransport.sendForAddr( m_context, addr, m_rowid,
gameID, buf );
int nSent = null == m_sink ? 0 : m_sink.numSent();
DbgUtils.showf( m_context, R.string.resend_finished_fmt, nSent );
}
}
}

View file

@ -27,8 +27,51 @@ import java.util.ArrayList;
import junit.framework.Assert;
import org.eehouse.android.xw4.jni.*;
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
public class MultiMsgSink implements TransportProcs {
private long m_rowid;
private Context m_context;
private int m_nSent = 0;
public MultiMsgSink( Context context, long rowid )
{
m_context = context;
m_rowid = rowid;
}
public MultiMsgSink( Context context )
{
this( context, 0 );
}
// rowID is used as token to identify game on relay. Anything that
// uniquely identifies a game on a device would work
public long getRowID() { return m_rowid; };
public void setRowID( long rowID ) { m_rowid = rowID; };
// These will be overridden by e.g. BTService which for sendViaBluetooth()
// can just insert a message into its queue
public int sendViaRelay( byte[] buf, int gameID )
{
Assert.assertTrue( XWApp.UDP_ENABLED );
return RelayService.sendPacket( m_context, getRowID(), buf );
}
public int sendViaBluetooth( byte[] buf, int gameID, CommsAddrRec addr )
{
return BTService.enqueueFor( m_context, buf, addr.bt_btAddr, gameID );
}
public int sendViaSMS( byte[] buf, int gameID, CommsAddrRec addr )
{
return SMSService.sendPacket( m_context, addr.sms_phone, gameID, buf );
}
public int numSent()
{
return m_nSent;
}
/***** TransportProcs interface *****/
@ -36,8 +79,35 @@ public class MultiMsgSink implements TransportProcs {
public int transportSend( byte[] buf, final CommsAddrRec addr, int gameID )
{
Assert.fail(); // implement if this is getting called!!!
return -1;
int maxSent = -1;
for ( CommsConnType typ : addr.conTypes.getTypes() ) {
int nSent = -1;
switch ( typ ) {
case COMMS_CONN_RELAY:
nSent = sendViaRelay( buf, gameID );
break;
case COMMS_CONN_BT:
nSent = sendViaBluetooth( buf, gameID, addr );
break;
case COMMS_CONN_SMS:
nSent = sendViaSMS( buf, gameID, addr );
break;
default:
Assert.fail();
break;
}
DbgUtils.logf( "MultiMsgSink.transportSend(): sent %d via %s",
nSent, typ.toString() );
if ( nSent > maxSent ) {
maxSent = nSent;
}
}
if ( 0 < maxSent ) {
++m_nSent;
}
return maxSent;
}
public void relayStatus( CommsRelayState newState )
@ -55,7 +125,9 @@ public class MultiMsgSink implements TransportProcs {
public boolean relayNoConnProc( byte[] buf, String relayID )
{
Assert.fail(); // implement if this is getting called!!!
return false;
Assert.fail();
int nSent = RelayService.sendNoConnPacket( m_context, getRowID(),
relayID, buf );
return buf.length == nSent;
}
}

View file

@ -47,6 +47,7 @@ import junit.framework.Assert;
import org.eehouse.android.xw4.MultiService.MultiEvent;
import org.eehouse.android.xw4.jni.CommsAddrRec;
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
import org.eehouse.android.xw4.jni.GameSummary;
import org.eehouse.android.xw4.jni.UtilCtxt;
import org.eehouse.android.xw4.jni.UtilCtxt.DevIDType;
@ -86,6 +87,8 @@ public class RelayService extends XWService
private static int s_nextPacketID = 1;
private static boolean s_gcmWorking = false;
private static boolean s_registered = false;
private static CommsAddrRec s_addr =
new CommsAddrRec( CommsConnType.COMMS_CONN_RELAY );
private Thread m_fetchThread = null;
private Thread m_UDPReadThread = null;
@ -849,14 +852,14 @@ public class RelayService extends XWService
{
DbgUtils.logf( "RelayService::feedMessage: %d bytes for rowid %d",
msg.length, rowid );
if ( BoardDelegate.feedMessage( rowid, msg ) ) {
if ( BoardDelegate.feedMessage( rowid, msg, s_addr ) ) {
DbgUtils.logf( "feedMessage: board ate it" );
// do nothing
} else {
RelayMsgSink sink = new RelayMsgSink();
sink.setRowID( rowid );
LastMoveInfo lmi = new LastMoveInfo();
if ( GameUtils.feedMessage( this, rowid, msg, null,
if ( GameUtils.feedMessage( this, rowid, msg, s_addr,
sink, lmi ) ) {
GameUtils.postMoveNotification( this, rowid, lmi );
} else {
@ -892,9 +895,9 @@ public class RelayService extends XWService
if ( null != forOne ) {
LastMoveInfo lmi = new LastMoveInfo();
sink.setRowID( rowIDs[ii] );
if ( BoardDelegate.feedMessages( rowIDs[ii], forOne )
if ( BoardDelegate.feedMessages( rowIDs[ii], forOne, s_addr )
|| GameUtils.feedMessages( this, rowIDs[ii],
forOne, null,
forOne, s_addr,
sink, lmi ) ) {
idsWMsgs.add( relayIDs[ii] );
lmis.add( lmi );
@ -1004,35 +1007,32 @@ public class RelayService extends XWService
} // sendToRelay
private class RelayMsgSink extends MultiMsgSink {
private HashMap<String,ArrayList<byte[]>> m_msgLists = null;
private long m_rowid = -1;
public void setRowID( long rowid ) { m_rowid = rowid; }
public RelayMsgSink() { super( RelayService.this ); }
public void send( Context context )
{
if ( -1 == m_rowid ) {
if ( -1 == getRowID() ) {
sendToRelay( context, m_msgLists );
} else {
Assert.assertNull( m_msgLists );
}
}
/***** TransportProcs interface *****/
public int transportSend( byte[] buf, final CommsAddrRec addr,
int gameID )
@Override
public int sendViaRelay( byte[] buf, int gameID )
{
Assert.assertTrue( -1 != m_rowid );
sendPacket( RelayService.this, m_rowid, buf );
Assert.assertTrue( -1 != getRowID() );
sendPacket( RelayService.this, getRowID(), buf );
return buf.length;
}
public boolean relayNoConnProc( byte[] buf, String relayID )
{
if ( -1 != m_rowid ) {
sendNoConnMessage( m_rowid, relayID, buf );
long rowID = getRowID();
if ( -1 != rowID ) {
sendNoConnMessage( rowID, relayID, buf );
} else {
if ( null == m_msgLists ) {
m_msgLists = new HashMap<String,ArrayList<byte[]>>();

View file

@ -883,29 +883,14 @@ public class SMSService extends XWService {
}
private class SMSMsgSink extends MultiMsgSink {
private Context m_context;
public SMSMsgSink( Context context ) {
super();
m_context = context;
super( context );
}
/***** TransportProcs interface *****/
public int transportSend( byte[] buf, final CommsAddrRec addr, int gameID )
@Override
public int sendViaSMS( byte[] buf, int gameID, CommsAddrRec addr )
{
int nSent = -1;
if ( null != addr ) {
nSent = sendPacket( addr.sms_phone, gameID, buf );
} else {
DbgUtils.logf( "SMSMsgSink.transportSend: "
+ "addr null so not sending" );
}
return nSent;
}
public boolean relayNoConnProc( byte[] buf, String relayID )
{
Assert.fail();
return false;
return sendPacket( addr.sms_phone, gameID, buf );
}
}

View file

@ -155,6 +155,11 @@ public class CommsAddrRec {
this.copyFrom( src );
}
public boolean contains( CommsConnType typ )
{
return null != conTypes && conTypes.contains( typ );
}
public void setRelayParams( String host, int port, String room )
{
setRelayParams( host, port );

View file

@ -391,6 +391,7 @@ public class JNIThread extends Thread {
case CMD_RECEIVE:
CommsAddrRec ret = (CommsAddrRec)args[1];
Assert.assertNotNull( ret );
draw = XwJNI.game_receiveMessage( m_jniGamePtr,
(byte[])args[0], ret );
handle( JNICmd.CMD_DO );