mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-09 05:24:44 +01:00
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:
parent
42575f1380
commit
a0beecafc3
8 changed files with 61 additions and 103 deletions
|
@ -826,13 +826,35 @@ public class DBUtils {
|
||||||
}
|
}
|
||||||
cursor.close();
|
cursor.close();
|
||||||
}
|
}
|
||||||
if ( null != result && 1 < result.length ) {
|
if ( 1 < result.length ) {
|
||||||
Log.i( TAG, "getRowIDsFor(%x)=>length %d array", gameID,
|
Log.i( TAG, "getRowIDsFor(%x)=>length %d array", gameID,
|
||||||
result.length );
|
result.length );
|
||||||
}
|
}
|
||||||
return result;
|
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 )
|
public static boolean haveGame( Context context, int gameID )
|
||||||
{
|
{
|
||||||
long[] rows = getRowIDsFor( context, 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 )
|
public static String[] getRelayIDs( Context context, long[][] rowIDs )
|
||||||
{
|
{
|
||||||
String[] result = null;
|
String[] result = null;
|
||||||
|
|
|
@ -2341,26 +2341,30 @@ public class GamesListDelegate extends ListDelegateBase
|
||||||
boolean handled = false;
|
boolean handled = false;
|
||||||
Assert.assertTrue( nli.isValid() );
|
Assert.assertTrue( nli.isValid() );
|
||||||
|
|
||||||
Date create = null;
|
Map<Long, Integer> rowids = DBUtils
|
||||||
create = DBUtils.getMostRecentCreate( m_activity, nli.gameID() );
|
.getRowIDsAndChannels( m_activity, nli.gameID() );
|
||||||
|
|
||||||
if ( null == create ) {
|
if ( 0 < rowids.size() ) {
|
||||||
if ( checkWarnNoDict( nli ) ) {
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !handled && checkWarnNoDict( nli ) ) {
|
||||||
makeNewNetGame( nli );
|
makeNewNetGame( nli );
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
} 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();
|
|
||||||
handled = true;
|
|
||||||
}
|
|
||||||
return handled;
|
return handled;
|
||||||
} // startNewNetGame
|
} // startNewNetGame
|
||||||
|
|
||||||
|
|
|
@ -57,11 +57,6 @@ public class XWPrefs {
|
||||||
BuildConfig.DEBUG );
|
BuildConfig.DEBUG );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean getSecondInviteAllowed( Context context )
|
|
||||||
{
|
|
||||||
return getPrefsBoolean( context, R.string.key_enable_dup_invite, false );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean moveCountEnabled( Context context )
|
public static boolean moveCountEnabled( Context context )
|
||||||
{
|
{
|
||||||
return getPrefsBoolean( context, R.string.key_enable_pending_count,
|
return getPrefsBoolean( context, R.string.key_enable_pending_count,
|
||||||
|
|
|
@ -135,48 +135,18 @@ abstract class XWServiceHelper {
|
||||||
} else {
|
} else {
|
||||||
success = true;
|
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 ) {
|
if ( success ) {
|
||||||
|
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" );
|
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()" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
success = false;
|
success = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( success ) {
|
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;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,8 @@ public class GameSummary implements Serializable {
|
||||||
public static final int MSG_FLAGS_GAMEOVER = 4;
|
public static final int MSG_FLAGS_GAMEOVER = 4;
|
||||||
public static final int MSG_FLAGS_ALL = 7;
|
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 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 lastMoveTime; // set by jni's server.c on move receipt
|
||||||
public int dupTimerExpires;
|
public int dupTimerExpires;
|
||||||
|
@ -372,6 +374,12 @@ public class GameSummary implements Serializable {
|
||||||
if ( m_gi.inDuplicateMode ) {
|
if ( m_gi.inDuplicateMode ) {
|
||||||
result |= DUP_MODE_MASK;
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,7 +133,6 @@
|
||||||
<string name="key_na_sms_invite_flakey">key_na_sms_invite_flakey</string>
|
<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_na_dicts">key_na_dicts</string>
|
||||||
<string name="key_enable_debug">key_enable_debug</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_pending_count">key_enable_pending_count</string>
|
||||||
<string name="key_enable_sms_toself">key_enable_sms_toself</string>
|
<string name="key_enable_sms_toself">key_enable_sms_toself</string>
|
||||||
<string name="key_show_fcm">key_show_fcm2</string>
|
<string name="key_show_fcm">key_show_fcm2</string>
|
||||||
|
|
|
@ -1268,16 +1268,6 @@
|
||||||
connect to the relay failed because the room named does not
|
connect to the relay failed because the room named does not
|
||||||
exist. (I believe this no longer occurs.) -->
|
exist. (I believe this no longer occurs.) -->
|
||||||
<string name="button_retry">Retry</string>
|
<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 -->
|
<!-- Title of generic dialog used to display information -->
|
||||||
<string name="info_title">FYI…</string>
|
<string name="info_title">FYI…</string>
|
||||||
<!-- title of dialog allowing user to pick tiles "face up". (This
|
<!-- 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_storedb">Write games to SD card</string>
|
||||||
<string name="gamel_menu_loaddb">Load games from 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="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="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_title">Show Pending messages</string>
|
||||||
<string name="enable_pending_count_summary">Show number not yet acknowledged</string>
|
<string name="enable_pending_count_summary">Show number not yet acknowledged</string>
|
||||||
<string name="nag_intervals">Reminder intervals (minutes1,minutes2,…)</string>
|
<string name="nag_intervals">Reminder intervals (minutes1,minutes2,…)</string>
|
||||||
|
|
|
@ -392,12 +392,6 @@
|
||||||
android:title="@string/nag_intervals"
|
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"
|
<CheckBoxPreference android:key="@string/key_enable_pending_count"
|
||||||
android:title="@string/enable_pending_count_title"
|
android:title="@string/enable_pending_count_title"
|
||||||
android:summary="@string/enable_pending_count_summary"
|
android:summary="@string/enable_pending_count_summary"
|
||||||
|
|
Loading…
Reference in a new issue