add function that resends all pending (un-ackd, at the comms level) messages for unlocked games and, for testing mostly, a menuitem on the main activity to trigger it. Probably crashes if there's a message for a game connected by other than relay.

This commit is contained in:
Eric House 2014-03-04 07:05:55 -08:00
parent 60bce8f22b
commit df771f50c4
7 changed files with 135 additions and 34 deletions

View file

@ -38,6 +38,9 @@
android:title="@string/board_menu_file_about"
android:icon="@android:drawable/ic_menu_info_details"
/>
<item android:id="@+id/games_menu_resend"
android:title="@string/board_menu_game_resend"
/>
<item android:id="@+id/games_menu_checkmoves"
android:title="@string/gamel_menu_checkmoves"
android:icon="@drawable/stat_notify_sync"

View file

@ -674,6 +674,7 @@
able to remove this from non-debug versions of the game
because users should not have to do do this EVER. -->
<string name="board_menu_game_resend">Resend messages</string>
<string name="resend_finishedf">Resend finished; sent %d message[s].</string>
<!--
############################################################

View file

@ -1018,12 +1018,6 @@ public class BTService extends XWService {
}
return sent;
}
public boolean relayNoConnProc( byte[] buf, String relayID )
{
Assert.fail();
return false;
}
}
}

View file

@ -50,6 +50,7 @@ import java.util.StringTokenizer;
import junit.framework.Assert;
import org.eehouse.android.xw4.jni.*;
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
import org.eehouse.android.xw4.DictUtils.DictLoc;
@ -204,7 +205,7 @@ public class DBUtils {
int col = cursor.getColumnIndex( DBHelper.CONTYPE );
if ( 0 <= col ) {
tmp = cursor.getInt( col );
summary.conType = CommsAddrRec.CommsConnType.values()[tmp];
summary.conType = CommsConnType.values()[tmp];
col = cursor.getColumnIndex( DBHelper.SEED );
if ( 0 < col ) {
summary.seed = cursor.getInt( col );
@ -499,27 +500,29 @@ public class DBUtils {
return result;
}
// Not read to use this yet
// public static long[] getGamesWithSendsPending( Context context )
// {
// long[] result = null;
// String[] columns = { ROW_ID };
// String selection = String.format( "%s > 0", DBHelper.NPACKETSPENDING );
// initDB( context );
// synchronized( s_dbHelper ) {
// SQLiteDatabase db = s_dbHelper.getReadableDatabase();
// Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
// selection, null, null, null, null );
// result = new long[cursor.getCount()];
// int indx = cursor.getColumnIndex( ROW_ID );
// for ( int ii = 0; cursor.moveToNext(); ++ii ) {
// result[ii] = cursor.getLong( indx );
// }
// cursor.close();
// db.close();
// }
// return result;
// }
public static HashMap<Long,CommsConnType>
getGamesWithSendsPending( Context context )
{
HashMap<Long, CommsConnType> result = new HashMap<Long,CommsConnType>();
String[] columns = { ROW_ID, DBHelper.CONTYPE };
String selection = String.format( "%s > 0", DBHelper.NPACKETSPENDING );
initDB( context );
synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
selection, null, null, null, null );
int indx1 = cursor.getColumnIndex( ROW_ID );
int indx2 = cursor.getColumnIndex( DBHelper.CONTYPE );
for ( int ii = 0; cursor.moveToNext(); ++ii ) {
long rowid = cursor.getLong( indx1 );
CommsConnType typ = CommsConnType.values()[cursor.getInt(indx2)];
result.put( rowid, typ );
}
cursor.close();
db.close();
}
return result;
}
public static long[] getRowIDsFor( Context context, String relayID )
{

View file

@ -26,6 +26,7 @@ import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.net.Uri;
import android.os.AsyncTask;
import android.text.Html;
import android.text.TextUtils;
@ -34,6 +35,7 @@ import java.io.File;
import java.io.FileOutputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.HashSet;
import java.util.concurrent.locks.Lock;
import org.json.JSONArray;
@ -42,6 +44,7 @@ import org.json.JSONObject;
import junit.framework.Assert;
import org.eehouse.android.xw4.jni.*;
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole;
public class GameUtils {
@ -98,7 +101,7 @@ public class GameUtils {
if ( XwJNI.game_hasComms( gamePtr ) ) {
addr = new CommsAddrRec();
XwJNI.comms_getAddr( gamePtr, addr );
if ( CommsAddrRec.CommsConnType.COMMS_CONN_NONE == addr.conType ) {
if ( CommsConnType.COMMS_CONN_NONE == addr.conType ) {
String relayName = XWPrefs.getDefaultRelayHost( context );
int relayPort = XWPrefs.getDefaultRelayPort( context );
XwJNI.comms_getInitialAddr( addr, relayName, relayPort );
@ -256,6 +259,12 @@ public class GameUtils {
return result;
}
public static int loadMakeGame( Context context, CurGameInfo gi,
TransportProcs tp, GameLock lock )
{
return loadMakeGame( context, gi, null, tp, lock );
}
public static int loadMakeGame( Context context, CurGameInfo gi,
GameLock lock )
{
@ -358,6 +367,12 @@ public class GameUtils {
return thumb;
}
public static void resendAll( Context context )
{
HashMap<Long,CommsConnType> games = DBUtils.getGamesWithSendsPending( context );
new ResendTask( context, games ).execute();
}
public static long saveGame( Context context, int gamePtr,
CurGameInfo gi, GameLock lock,
boolean setCreate )
@ -522,7 +537,7 @@ public class GameUtils {
String[] dicta = { dict };
boolean isHost = null == addr;
if ( isHost ) {
addr = new CommsAddrRec(CommsAddrRec.CommsConnType.COMMS_CONN_SMS);
addr = new CommsAddrRec( CommsConnType.COMMS_CONN_SMS );
}
String inviteID = GameUtils.formatGameID( gameID );
return makeNewMultiGame( context, groupID, addr, langa, dicta,
@ -964,4 +979,64 @@ public class GameUtils {
return result;
}
private static class ResendTask extends AsyncTask<Void, Void, Void> {
private Context m_context;
private HashMap<Long,CommsConnType> m_games;
private int m_nSent = 0;
public ResendTask( Context context, HashMap<Long,CommsConnType> games )
{
m_context = context;
m_games = games;
}
@Override
protected Void doInBackground( Void... unused )
{
Iterator<Long> iter = m_games.keySet().iterator();
while ( iter.hasNext() ) {
long rowid = iter.next();
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 );
if ( 0 != gamePtr ) {
XwJNI.comms_resendAll( gamePtr, true, false );
}
lock.unlock();
}
}
return null;
}
@Override
protected void onPostExecute( Void unused )
{
DbgUtils.showf( m_context, R.string.resend_finishedf, 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;
}
}
}
}

View file

@ -98,6 +98,7 @@ public class GamesList extends XWExpandableListActivity
// R.id.games_menu_loaddb,
R.id.games_menu_storedb,
R.id.games_menu_checkupdates,
R.id.games_menu_resend,
};
private static final int[] NOSEL_ITEMS = {
R.id.games_menu_newgroup,
@ -679,7 +680,7 @@ public class GamesList extends XWExpandableListActivity
if ( m_menuPrepared ) {
boolean nothingSelected = 0 == (nGroupsSelected + nGamesSelected);
boolean showDbg = BuildConfig.DEBUG
final boolean showDbg = BuildConfig.DEBUG
|| XWPrefs.getDebugEnabled( this );
showItemsIf( DEBUG_ITEMS, menu, nothingSelected && showDbg );
Utils.setItemVisible( menu, R.id.games_menu_loaddb,
@ -762,6 +763,9 @@ public class GamesList extends XWExpandableListActivity
switch ( item.getItemId() ) {
// There's no selection for these items, so nothing to clear
case R.id.games_menu_resend:
GameUtils.resendAll( this );
break;
case R.id.games_menu_newgame:
startNewGameActivity( groupID );
break;

View file

@ -68,6 +68,7 @@ public class RelayService extends XWService
, PROCESS_DEV_MSGS
, UDP_CHANGED
, SEND
, SENDNOCONN
, RECEIVE
, TIMER_FIRED
, RESET
@ -173,6 +174,21 @@ public class RelayService extends XWService
return result;
}
public static int sendNoConnPacket( Context context, long rowid, String relayID,
byte[] msg )
{
int result = -1;
if ( NetStateCache.netAvail( context ) ) {
Intent intent = getIntentTo( context, MsgCmds.SENDNOCONN )
.putExtra( ROWID, rowid )
.putExtra( RELAY_ID, relayID )
.putExtra( BINBUFFER, msg );
context.startService( intent );
result = msg.length;
}
return result;
}
public static void devIDChanged()
{
s_registered = false;
@ -290,11 +306,15 @@ public class RelayService extends XWService
break;
case SEND:
case RECEIVE:
case SENDNOCONN:
startUDPThreadsIfNot();
long rowid = intent.getLongExtra( ROWID, -1 );
byte[] msg = intent.getByteArrayExtra( BINBUFFER );
if ( MsgCmds.SEND.equals( cmd ) ) {
sendMessage( rowid, msg );
} else if ( MsgCmds.SENDNOCONN.equals( cmd ) ) {
String relayID = intent.getStringExtra( RELAY_ID );
sendNoConnMessage( rowid, relayID, msg );
} else {
feedMessage( rowid, msg );
}
@ -462,7 +482,7 @@ public class RelayService extends XWService
if ( null == m_UDPWriteThread ) {
m_UDPWriteThread = new Thread( null, new Runnable() {
public void run() {
DbgUtils.logf( "RelayService: write thread running" );
DbgUtils.logf( "RelayService: write thread starting" );
for ( ; ; ) {
PacketData outData;
try {
@ -740,7 +760,7 @@ public class RelayService extends XWService
ByteArrayOutputStream bas = new ByteArrayOutputStream();
try {
DataOutputStream out = new DataOutputStream( bas );
Assert.assertTrue( rowid < Integer.MAX_VALUE );
Assert.assertTrue( rowid < Integer.MAX_VALUE ); // ???
out.writeInt( (int)rowid );
out.writeBytes( relayID );
out.write( '\n' );
@ -797,7 +817,8 @@ public class RelayService extends XWService
private void postPacket( ByteArrayOutputStream bas, XWRelayReg cmd )
{
m_queue.add( new PacketData( bas, cmd ) );
DbgUtils.logf( "postPacket() done; %d in queue", m_queue.size() );
// 0 ok; thread will often have sent already!
// DbgUtils.logf( "postPacket() done; %d in queue", m_queue.size() );
}
private String getDevID( DevIDType[] typp )