diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BTService.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BTService.java index 039e2cb78..ab3e6b027 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BTService.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BTService.java @@ -48,6 +48,7 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -119,6 +120,7 @@ public class BTService extends XWJIService { }; private static final String MSG_KEY = "MSG"; + private static final String MSGID_KEY = "MSGID"; private static final String GAMENAME_KEY = "NAM"; private static final String ADDR_KEY = "ADR"; private static final String SCAN_TIMEOUT_KEY = "SCAN_TIMEOUT"; @@ -333,7 +335,7 @@ public class BTService extends XWJIService { enqueueWork( context, intent ); } - public static int sendPacket( Context context, byte[] buf, + public static int sendPacket( Context context, byte[] buf, String msgID, CommsAddrRec targetAddr, int gameID ) { int nSent = -1; @@ -342,6 +344,7 @@ public class BTService extends XWJIService { if ( null != btAddr && 0 < btAddr.length() ) { Intent intent = getIntentTo( context, BTAction.SEND ) .putExtra( MSG_KEY, buf ) + .putExtra( MSGID_KEY, msgID ) .putExtra( ADDR_KEY, btAddr ) .putExtra( GAMEID_KEY, gameID ); enqueueWork( context, intent ); @@ -447,9 +450,10 @@ public class BTService extends XWJIService { case SEND: byte[] buf = intent.getByteArrayExtra( MSG_KEY ); btAddr = intent.getStringExtra( ADDR_KEY ); + String msgID = intent.getStringExtra( MSGID_KEY ); gameID = intent.getIntExtra( GAMEID_KEY, -1 ); if ( -1 != gameID ) { - getSenderFor( btAddr ).addMsg( gameID, buf ); + getSenderFor( btAddr ).addMsg( gameID, buf, msgID ); } break; case RADIO: @@ -1076,12 +1080,13 @@ public class BTService extends XWJIService { public BTMsgSink() { super( BTService.this ); } @Override - public int sendViaBluetooth( byte[] buf, int gameID, CommsAddrRec addr ) + public int sendViaBluetooth( byte[] buf, String msgID, int gameID, + CommsAddrRec addr ) { int nSent = -1; String btAddr = getSafeAddr( addr ); if ( null != btAddr && 0 < btAddr.length() ) { - getSenderFor( btAddr ).addMsg( gameID, buf ); + getSenderFor( btAddr ).addMsg( gameID, buf, msgID ); BTSenderThread.startYourself( BTService.this ); nSent = buf.length; } else { @@ -1122,13 +1127,15 @@ public class BTService extends XWJIService { private static class MsgElem { BTCmd mCmd; + String mMsgID; int mGameID; long mStamp; byte[] mData; - MsgElem( BTCmd cmd, int gameID, OutputPair op ) + MsgElem( BTCmd cmd, int gameID, String msgID, OutputPair op ) { mCmd = cmd; + mMsgID = msgID; mGameID = gameID; mStamp = System.currentTimeMillis(); @@ -1148,7 +1155,27 @@ public class BTService extends XWJIService { } } + boolean isSameAs( MsgElem other ) + { + boolean result = mCmd == other.mCmd + && mGameID == other.mGameID + && Arrays.equals( mData, other.mData ); + if ( result ) { + if ( null != mMsgID && !mMsgID.equals( other.mMsgID ) ) { + Log.e( TAG, "hmmm: identical but msgIDs differ: new %s vs old %s", + mMsgID, other.mMsgID ); + Assert.assertFalse( BuildConfig.DEBUG ); + } + } + return result; + } + int size() { return mData.length; } + @Override + public String toString() + { + return String.format("{cmd: %s, msgID: %s}", mCmd, mMsgID ); + } } private String mAddr; @@ -1382,14 +1409,14 @@ public class BTService extends XWJIService { } } - void addMsg( int gameID, byte[] buf ) + void addMsg( int gameID, byte[] buf, String msgID ) { try { OutputPair op = new OutputPair(); op.dos.writeInt( gameID ); op.dos.writeShort( buf.length ); op.dos.write( buf, 0, buf.length ); - append( BTCmd.MESG_SEND, gameID, op ); + append( BTCmd.MESG_SEND, gameID, msgID, op ); } catch ( IOException ioe ) { Assert.assertFalse( BuildConfig.DEBUG ); } @@ -1408,20 +1435,40 @@ public class BTService extends XWJIService { private void append( BTCmd cmd, OutputPair op ) throws IOException { - append( cmd, 0, op ); + append( cmd, 0, null, op ); + } + + private void append( BTCmd cmd, int gameID, OutputPair op ) throws IOException + { + append( cmd, gameID, null, op ); } - private boolean append( BTCmd cmd, int gameID, OutputPair op ) throws IOException + private boolean append( BTCmd cmd, int gameID, String msgID, + OutputPair op ) throws IOException { boolean haveSpace; try ( DbgUtils.DeadlockWatch dw = new DbgUtils.DeadlockWatch( this ) ) { synchronized ( this ) { - MsgElem newElem = new MsgElem( cmd, gameID, op ); + MsgElem newElem = new MsgElem( cmd, gameID, msgID, op ); haveSpace = mLength + newElem.size() < MAX_PACKET_LEN; if ( haveSpace ) { - mElems.add( newElem ); - mLength += newElem.size(); - mFailCount = 0; // for now, we restart timer on new data + // Let's check for duplicates.... + boolean dupFound = false; + for ( MsgElem elem : mElems ) { + if ( elem.isSameAs( newElem ) ) { + dupFound = true; + break; + } + } + + if ( dupFound ) { + Log.d( TAG, "append(): dropping dupe: %s", newElem ); + } else { + mElems.add( newElem ); + mLength += newElem.size(); + } + // for now, we restart timer on new data, even if a dupe + mFailCount = 0; tellSomebody(); } } diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/CommsTransport.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/CommsTransport.java index 779ca0839..85abbe41e 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/CommsTransport.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/CommsTransport.java @@ -354,7 +354,7 @@ public class CommsTransport implements TransportProcs, } @Override - public int transportSend( byte[] buf, String msgNo, CommsAddrRec addr, + public int transportSend( byte[] buf, String msgID, CommsAddrRec addr, CommsConnType conType, int gameID ) { Log.d( TAG, "transportSend(len=%d, typ=%s)", buf.length, @@ -380,7 +380,7 @@ public class CommsTransport implements TransportProcs, } } else { nSent = sendForAddr( m_context, addr, conType, m_rowid, - gameID, buf ); + gameID, buf, msgID ); } // Keep this while debugging why the resend_all that gets @@ -404,20 +404,20 @@ public class CommsTransport implements TransportProcs, } @Override - public boolean relayNoConnProc( byte[] buf, String msgNo, String relayID ) + public boolean relayNoConnProc( byte[] buf, String msgID, String relayID ) { Assert.assertTrue( TRANSPORT_DOES_NOCONN ); int nSent = RelayService.sendNoConnPacket( m_context, m_rowid, - relayID, buf, msgNo ); + relayID, buf, msgID ); boolean success = buf.length == nSent; - Log.d( TAG, "relayNoConnProc(msgNo=%s, len=%d) => %b", msgNo, + Log.d( TAG, "relayNoConnProc(msgID=%s, len=%d) => %b", msgID, buf.length, success ); return success; } private static int sendForAddr( Context context, CommsAddrRec addr, CommsConnType conType, long rowID, - int gameID, byte[] buf ) + int gameID, byte[] buf, String msgID ) { int nSent = -1; switch ( conType ) { @@ -430,7 +430,7 @@ public class CommsTransport implements TransportProcs, gameID, buf ); break; case COMMS_CONN_BT: - nSent = BTService.sendPacket( context, buf, addr, gameID ); + nSent = BTService.sendPacket( context, buf, msgID, addr, gameID ); break; case COMMS_CONN_P2P: nSent = WiDirService diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/MultiMsgSink.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/MultiMsgSink.java index d1f36570d..a1840390c 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/MultiMsgSink.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/MultiMsgSink.java @@ -62,9 +62,10 @@ public class MultiMsgSink implements TransportProcs { return RelayService.sendPacket( m_context, getRowID(), buf ); } - public int sendViaBluetooth( byte[] buf, int gameID, CommsAddrRec addr ) + public int sendViaBluetooth( byte[] buf, String msgID, int gameID, + CommsAddrRec addr ) { - return BTService.sendPacket( m_context, buf, addr, gameID ); + return BTService.sendPacket( m_context, buf, msgID, addr, gameID ); } public int sendViaSMS( byte[] buf, int gameID, CommsAddrRec addr ) @@ -88,7 +89,7 @@ public class MultiMsgSink implements TransportProcs { public int getFlags() { return COMMS_XPORT_FLAGS_HASNOCONN; } @Override - public int transportSend( byte[] buf, String msgNo, CommsAddrRec addr, + public int transportSend( byte[] buf, String msgID, CommsAddrRec addr, CommsConnType typ, int gameID ) { int nSent = -1; @@ -97,7 +98,7 @@ public class MultiMsgSink implements TransportProcs { nSent = sendViaRelay( buf, gameID ); break; case COMMS_CONN_BT: - nSent = sendViaBluetooth( buf, gameID, addr ); + nSent = sendViaBluetooth( buf, msgID, gameID, addr ); break; case COMMS_CONN_SMS: nSent = sendViaSMS( buf, gameID, addr ); @@ -112,8 +113,8 @@ public class MultiMsgSink implements TransportProcs { Log.i( TAG, "transportSend(): sent %d msgs for game %d/%x via %s", nSent, gameID, gameID, typ.toString() ); if ( 0 < nSent ) { - Log.d( TAG, "transportSend: adding %s", msgNo ); - m_sentSet.add( msgNo ); + Log.d( TAG, "transportSend: adding %s", msgID ); + m_sentSet.add( msgID ); } return nSent;