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:title="@string/board_menu_file_about"
android:icon="@android:drawable/ic_menu_info_details" 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" <item android:id="@+id/games_menu_checkmoves"
android:title="@string/gamel_menu_checkmoves" android:title="@string/gamel_menu_checkmoves"
android:icon="@drawable/stat_notify_sync" android:icon="@drawable/stat_notify_sync"

View file

@ -674,6 +674,7 @@
able to remove this from non-debug versions of the game able to remove this from non-debug versions of the game
because users should not have to do do this EVER. --> because users should not have to do do this EVER. -->
<string name="board_menu_game_resend">Resend messages</string> <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; 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 junit.framework.Assert;
import org.eehouse.android.xw4.jni.*; import org.eehouse.android.xw4.jni.*;
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
import org.eehouse.android.xw4.DictUtils.DictLoc; import org.eehouse.android.xw4.DictUtils.DictLoc;
@ -204,7 +205,7 @@ public class DBUtils {
int col = cursor.getColumnIndex( DBHelper.CONTYPE ); int col = cursor.getColumnIndex( DBHelper.CONTYPE );
if ( 0 <= col ) { if ( 0 <= col ) {
tmp = cursor.getInt( col ); tmp = cursor.getInt( col );
summary.conType = CommsAddrRec.CommsConnType.values()[tmp]; summary.conType = CommsConnType.values()[tmp];
col = cursor.getColumnIndex( DBHelper.SEED ); col = cursor.getColumnIndex( DBHelper.SEED );
if ( 0 < col ) { if ( 0 < col ) {
summary.seed = cursor.getInt( col ); summary.seed = cursor.getInt( col );
@ -499,27 +500,29 @@ public class DBUtils {
return result; return result;
} }
// Not read to use this yet public static HashMap<Long,CommsConnType>
// public static long[] getGamesWithSendsPending( Context context ) getGamesWithSendsPending( Context context )
// { {
// long[] result = null; HashMap<Long, CommsConnType> result = new HashMap<Long,CommsConnType>();
// String[] columns = { ROW_ID }; String[] columns = { ROW_ID, DBHelper.CONTYPE };
// String selection = String.format( "%s > 0", DBHelper.NPACKETSPENDING ); String selection = String.format( "%s > 0", DBHelper.NPACKETSPENDING );
// initDB( context ); initDB( context );
// synchronized( s_dbHelper ) { synchronized( s_dbHelper ) {
// SQLiteDatabase db = s_dbHelper.getReadableDatabase(); SQLiteDatabase db = s_dbHelper.getReadableDatabase();
// Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns, Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
// selection, null, null, null, null ); selection, null, null, null, null );
// result = new long[cursor.getCount()]; int indx1 = cursor.getColumnIndex( ROW_ID );
// int indx = cursor.getColumnIndex( ROW_ID ); int indx2 = cursor.getColumnIndex( DBHelper.CONTYPE );
// for ( int ii = 0; cursor.moveToNext(); ++ii ) { for ( int ii = 0; cursor.moveToNext(); ++ii ) {
// result[ii] = cursor.getLong( indx ); long rowid = cursor.getLong( indx1 );
// } CommsConnType typ = CommsConnType.values()[cursor.getInt(indx2)];
// cursor.close(); result.put( rowid, typ );
// db.close(); }
// } cursor.close();
// return result; db.close();
// } }
return result;
}
public static long[] getRowIDsFor( Context context, String relayID ) 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.Bitmap;
import android.graphics.Rect; import android.graphics.Rect;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask;
import android.text.Html; import android.text.Html;
import android.text.TextUtils; import android.text.TextUtils;
@ -34,6 +35,7 @@ import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.HashSet; import java.util.HashSet;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Lock;
import org.json.JSONArray; import org.json.JSONArray;
@ -42,6 +44,7 @@ import org.json.JSONObject;
import junit.framework.Assert; import junit.framework.Assert;
import org.eehouse.android.xw4.jni.*; import org.eehouse.android.xw4.jni.*;
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole; import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole;
public class GameUtils { public class GameUtils {
@ -98,7 +101,7 @@ public class GameUtils {
if ( XwJNI.game_hasComms( gamePtr ) ) { if ( XwJNI.game_hasComms( gamePtr ) ) {
addr = new CommsAddrRec(); addr = new CommsAddrRec();
XwJNI.comms_getAddr( gamePtr, addr ); 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 ); String relayName = XWPrefs.getDefaultRelayHost( context );
int relayPort = XWPrefs.getDefaultRelayPort( context ); int relayPort = XWPrefs.getDefaultRelayPort( context );
XwJNI.comms_getInitialAddr( addr, relayName, relayPort ); XwJNI.comms_getInitialAddr( addr, relayName, relayPort );
@ -256,6 +259,12 @@ public class GameUtils {
return result; 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, public static int loadMakeGame( Context context, CurGameInfo gi,
GameLock lock ) GameLock lock )
{ {
@ -358,6 +367,12 @@ public class GameUtils {
return thumb; 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, public static long saveGame( Context context, int gamePtr,
CurGameInfo gi, GameLock lock, CurGameInfo gi, GameLock lock,
boolean setCreate ) boolean setCreate )
@ -522,7 +537,7 @@ public class GameUtils {
String[] dicta = { dict }; String[] dicta = { dict };
boolean isHost = null == addr; boolean isHost = null == addr;
if ( isHost ) { if ( isHost ) {
addr = new CommsAddrRec(CommsAddrRec.CommsConnType.COMMS_CONN_SMS); addr = new CommsAddrRec( CommsConnType.COMMS_CONN_SMS );
} }
String inviteID = GameUtils.formatGameID( gameID ); String inviteID = GameUtils.formatGameID( gameID );
return makeNewMultiGame( context, groupID, addr, langa, dicta, return makeNewMultiGame( context, groupID, addr, langa, dicta,
@ -964,4 +979,64 @@ public class GameUtils {
return result; 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_loaddb,
R.id.games_menu_storedb, R.id.games_menu_storedb,
R.id.games_menu_checkupdates, R.id.games_menu_checkupdates,
R.id.games_menu_resend,
}; };
private static final int[] NOSEL_ITEMS = { private static final int[] NOSEL_ITEMS = {
R.id.games_menu_newgroup, R.id.games_menu_newgroup,
@ -679,7 +680,7 @@ public class GamesList extends XWExpandableListActivity
if ( m_menuPrepared ) { if ( m_menuPrepared ) {
boolean nothingSelected = 0 == (nGroupsSelected + nGamesSelected); boolean nothingSelected = 0 == (nGroupsSelected + nGamesSelected);
boolean showDbg = BuildConfig.DEBUG final boolean showDbg = BuildConfig.DEBUG
|| XWPrefs.getDebugEnabled( this ); || XWPrefs.getDebugEnabled( this );
showItemsIf( DEBUG_ITEMS, menu, nothingSelected && showDbg ); showItemsIf( DEBUG_ITEMS, menu, nothingSelected && showDbg );
Utils.setItemVisible( menu, R.id.games_menu_loaddb, Utils.setItemVisible( menu, R.id.games_menu_loaddb,
@ -762,6 +763,9 @@ public class GamesList extends XWExpandableListActivity
switch ( item.getItemId() ) { switch ( item.getItemId() ) {
// There's no selection for these items, so nothing to clear // 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: case R.id.games_menu_newgame:
startNewGameActivity( groupID ); startNewGameActivity( groupID );
break; break;

View file

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