Don't accept invitation again for same channel

Do away with debug setting to accept duplicate invitations. Change
definition of duplicate to mean specifying a channel and gameID that
already exist. So now send-to-self works without a debug
preference. Accidentally clicking on the same emailed invite twice will
still be blocked. There will be problems if a game's been deleted but
those have probably always been here.
This commit is contained in:
Eric House 2020-08-29 16:11:24 -07:00
parent 42575f1380
commit a0beecafc3
8 changed files with 61 additions and 103 deletions

View file

@ -826,13 +826,35 @@ public class DBUtils {
}
cursor.close();
}
if ( null != result && 1 < result.length ) {
if ( 1 < result.length ) {
Log.i( TAG, "getRowIDsFor(%x)=>length %d array", gameID,
result.length );
}
return result;
}
static Map<Long, Integer> getRowIDsAndChannels( Context context, int gameID )
{
Map<Long, Integer> result = new HashMap<>();
String[] columns = { ROW_ID, DBHelper.GIFLAGS };
String selection = String.format( DBHelper.GAMEID + "=%d", gameID );
initDB( context );
synchronized( s_dbHelper ) {
Cursor cursor = query( TABLE_NAMES.SUM, columns, selection );
while ( cursor.moveToNext() ) {
int flags = cursor.getInt( cursor.getColumnIndex( DBHelper.GIFLAGS ) );
int forceChannel = (flags >> GameSummary.FORCE_CHANNEL_OFFSET)
& GameSummary.FORCE_CHANNEL_MASK;
long rowid = cursor.getLong( cursor.getColumnIndex( ROW_ID ) );
result.put( rowid, forceChannel );
// Log.i( TAG, "getRowIDsAndChannels(): added %d => %d",
// rowid, forceChannel );
}
cursor.close();
}
return result;
}
public static boolean haveGame( Context context, int gameID )
{
long[] rows = getRowIDsFor( context, gameID );
@ -900,28 +922,6 @@ public class DBUtils {
}
}
// Return creation time of newest game matching this nli, or null
// if none found.
public static Date getMostRecentCreate( Context context, int gameID )
{
Date result = null;
String selection = String.format("%s=%d", DBHelper.GAMEID, gameID );
String[] columns = { DBHelper.CREATE_TIME };
initDB( context );
synchronized( s_dbHelper ) {
Cursor cursor = query( TABLE_NAMES.SUM, columns, selection );
if ( cursor.moveToNext() ) {
int indx = cursor.getColumnIndex( columns[0] );
result = new Date( cursor.getLong( indx ) );
}
cursor.close();
}
return result;
}
public static String[] getRelayIDs( Context context, long[][] rowIDs )
{
String[] result = null;

View file

@ -2341,26 +2341,30 @@ public class GamesListDelegate extends ListDelegateBase
boolean handled = false;
Assert.assertTrue( nli.isValid() );
Date create = null;
create = DBUtils.getMostRecentCreate( m_activity, nli.gameID() );
Map<Long, Integer> rowids = DBUtils
.getRowIDsAndChannels( m_activity, nli.gameID() );
if ( null == create ) {
if ( checkWarnNoDict( nli ) ) {
makeNewNetGame( nli );
handled = true;
if ( 0 < rowids.size() ) {
// There's already a game? Better not have same channel as invite
// creates
for ( long rowid : rowids.keySet() ) {
if ( nli.forceChannel == rowids.get(rowid) ) {
// May not want this at all if it's never a bad thing
makeOkOnlyBuilder( R.string.dropped_dupe )
.setParams(rowid)
.setTitle("add open game button")
.show();
handled = true;
break;
}
}
} else if ( XWPrefs.getSecondInviteAllowed( m_activity ) ) {
String msg = getString( R.string.dup_game_query_fmt,
create.toString() );
m_netLaunchInfo = nli;
makeConfirmThenBuilder( msg, Action.NEW_NET_GAME )
.setParams( nli )
.show();
handled = true;
} else {
makeOkOnlyBuilder( R.string.dropped_dupe ).show();
}
if ( !handled && checkWarnNoDict( nli ) ) {
makeNewNetGame( nli );
handled = true;
}
return handled;
} // startNewNetGame

View file

@ -57,11 +57,6 @@ public class XWPrefs {
BuildConfig.DEBUG );
}
public static boolean getSecondInviteAllowed( Context context )
{
return getPrefsBoolean( context, R.string.key_enable_dup_invite, false );
}
public static boolean moveCountEnabled( Context context )
{
return getPrefsBoolean( context, R.string.key_enable_pending_count,

View file

@ -135,48 +135,18 @@ abstract class XWServiceHelper {
} else {
success = true;
}
CurGameInfo gi = null;
if ( success ) {
long[] rowids = DBUtils.getRowIDsFor( mContext, nli.gameID() );
if ( 0 == rowids.length ) {
// cool: we're good
} else if ( rowids.length < nli.nPlayersT ) {
success = XWPrefs.getSecondInviteAllowed( mContext );
if ( BuildConfig.DEBUG && !success ) {
DbgUtils.showf( mContext, "Dropping duplicate invite" );
}
// Allowing a second game allows the common testing action of
// sending invitation to myself. But we still need to check
// for duplicates! forceChannel's hard to dig up, but works
for ( int ii = 0; success && ii < rowids.length; ++ii ) {
long rowid = rowids[ii];
try ( GameLock lock = GameLock.tryLockRO( rowid ) ) {
// drop invite if can't open game; likely a dupe!
if ( null != lock ) {
gi = new CurGameInfo( mContext );
GamePtr gamePtr = GameUtils
.loadMakeGame( mContext, gi, lock );
gamePtr.release();
} else {
DbgUtils.toastNoLock( TAG, mContext, rowid,
"handleInvitation()" );
}
Map<Long, Integer> rowids = DBUtils.getRowIDsAndChannels( mContext, nli.gameID() );
// Accept only if there isn't already a game with the channel
for ( long rowid : rowids.keySet() ) {
if ( rowids.get( rowid ) == nli.forceChannel ) {
if ( BuildConfig.DEBUG ) {
DbgUtils.showf( mContext, "Dropping duplicate invite" );
}
if ( null == gi ) {
// locked. Maybe it's open?
try ( JNIThread thrd = JNIThread.getRetained( rowid ) ) {
if ( null != thrd ) {
gi = thrd.getGI();
}
}
}
success = null != gi && gi.forceChannel != nli.forceChannel;
success = false;
break;
}
} else {
success = false;
}
if ( success ) {
@ -198,7 +168,7 @@ abstract class XWServiceHelper {
}
}
}
Log.d( TAG, "handleInvitation() => %b (gi: %s)", success, gi );
Log.d( TAG, "handleInvitation() => %b", success );
return success;
}

View file

@ -58,6 +58,8 @@ public class GameSummary implements Serializable {
public static final int MSG_FLAGS_GAMEOVER = 4;
public static final int MSG_FLAGS_ALL = 7;
public static final int DUP_MODE_MASK = 1 << (CurGameInfo.MAX_NUM_PLAYERS * 2);
public static final int FORCE_CHANNEL_OFFSET = (CurGameInfo.MAX_NUM_PLAYERS * 2) + 1;
public static final int FORCE_CHANNEL_MASK = 0x03;
public int lastMoveTime; // set by jni's server.c on move receipt
public int dupTimerExpires;
@ -372,6 +374,12 @@ public class GameSummary implements Serializable {
if ( m_gi.inDuplicateMode ) {
result |= DUP_MODE_MASK;
}
Assert.assertTrue( (result & (FORCE_CHANNEL_MASK<<FORCE_CHANNEL_OFFSET)) == 0 );
// Make sure it's big enough
Assert.assertTrue( 0 == (~FORCE_CHANNEL_MASK & m_gi.forceChannel) );
result |= m_gi.forceChannel << FORCE_CHANNEL_OFFSET;
Log.d( TAG, "giflags(): adding forceChannel %d", m_gi.forceChannel );
}
return result;
}

View file

@ -133,7 +133,6 @@
<string name="key_na_sms_invite_flakey">key_na_sms_invite_flakey</string>
<string name="key_na_dicts">key_na_dicts</string>
<string name="key_enable_debug">key_enable_debug</string>
<string name="key_enable_dup_invite">key_enable_dup_invite</string>
<string name="key_enable_pending_count">key_enable_pending_count</string>
<string name="key_enable_sms_toself">key_enable_sms_toself</string>
<string name="key_show_fcm">key_show_fcm2</string>

View file

@ -1268,16 +1268,6 @@
connect to the relay failed because the room named does not
exist. (I believe this no longer occurs.) -->
<string name="button_retry">Retry</string>
<!-- Shown in the main screen when you launch CrossWords from an
invitation (received in email or messaging app, say) and
there's already a game running that matches that invitation.
It's to prevent you from opening multiple games and getting
confused. But some people who play together all the time use
the same room name over and over so they'll get this warning
and it's harmless to ignore it. -->
<string name="dup_game_query_fmt">You already have a game that seems
to have been created (on %1$s) from the same invitation. Are you
sure you want to create another?</string>
<!-- Title of generic dialog used to display information -->
<string name="info_title">FYI…</string>
<!-- title of dialog allowing user to pick tiles "face up". (This
@ -2277,9 +2267,7 @@
<string name="gamel_menu_storedb">Write games to SD card</string>
<string name="gamel_menu_loaddb">Load games from SD card</string>
<string name="gamel_menu_writegit">Copy git info to clipboard</string>
<string name="enable_dupes_title">Accept duplicate invites</string>
<string name="xlations_locale">Fake locale for translation</string>
<string name="enable_dupes_summary">Accept invitations more than once</string>
<string name="enable_pending_count_title">Show Pending messages</string>
<string name="enable_pending_count_summary">Show number not yet acknowledged</string>
<string name="nag_intervals">Reminder intervals (minutes1,minutes2,…)</string>

View file

@ -392,12 +392,6 @@
android:title="@string/nag_intervals"
/>
<CheckBoxPreference android:key="@string/key_enable_dup_invite"
android:title="@string/enable_dupes_title"
android:summary="@string/enable_dupes_summary"
android:defaultValue="@bool/DEBUG"
/>
<CheckBoxPreference android:key="@string/key_enable_pending_count"
android:title="@string/enable_pending_count_title"
android:summary="@string/enable_pending_count_summary"