Merge branch 'android_branch' of ssh://git.code.sf.net/p/xwords/git into android_branch

Conflicts:
	xwords4/android/scripts/info.py
This commit is contained in:
Eric House 2015-07-25 22:03:05 -07:00
commit 2e6154e920
53 changed files with 1769 additions and 1260 deletions

File diff suppressed because it is too large Load diff

View file

@ -41,6 +41,12 @@
at all times you can use to invite players. The dialog goes at all times you can use to invite players. The dialog goes
away when invited players connect.</li> away when invited players connect.</li>
<li>But when a game hasn&apos;t connected yet, warn, and
don&apos;t let it send an invitation</li>
<li>On startup, if on a phone configured for other than English,
offer to download an appropriate wordlist</li>
<li>New games are placed in the selected group (if any, <li>New games are placed in the selected group (if any,
otherwise in default as before)</li> otherwise in default as before)</li>
@ -60,7 +66,8 @@
it too hard to support this, and non-GSM phones are only it too hard to support this, and non-GSM phones are only
found in one country anyway.)</li> found in one country anyway.)</li>
<li>Deal with deletion of dictionary that's been set as default</li> <li>Deal with deletion of dictionary that&apos;s been set as
default</li>
<li>In popup menu from in-game wordlist button, show only <li>In popup menu from in-game wordlist button, show only
wordlists in same language as game</li> wordlists in same language as game</li>
@ -68,13 +75,13 @@
<li>When assigning new tiles, don&apos;t sort tiles to left of <li>When assigning new tiles, don&apos;t sort tiles to left of
tray divider</li> tray divider</li>
<li>Don&apos;t post empty notifications</li>
<li>Remove &quot;Reconnect&quot; button from network status info</li> <li>Remove &quot;Reconnect&quot; button from network status info</li>
<li>Include info for all communication means being used in <li>Include info for all communication means being used in
network status, and only show an icon in networked games </li> network status, and only show an icon in networked games </li>
<li>Show status message after writing to SD card</li>
<li>Fix a few crashes</li> <li>Fix a few crashes</li>
</ul> </ul>
@ -89,10 +96,11 @@
<li>Look into supporting play via peer-to-peer wifi</li> <li>Look into supporting play via peer-to-peer wifi</li>
</ul> </ul>
<p>Please let me know (email eehouse@eehouse.org) what&apos;s broken <p>Please let me know
and what features you&apos;d most like to see. And if you do get (email <a href="mailto:xwords@eehouse.org">xwords@eehouse.org</a>)
a crash, please let your device report it to Google so I can see what&apos;s broken and what features you&apos;d most like to
it!</p> see. And if you do get a crash, please let your device report it
to Google so I can see it!</p>
<p>Thanks!<br>--Eric</p> <p>Thanks!<br>--Eric</p>

View file

@ -431,12 +431,9 @@ and_util_getUserString( XW_UtilCtxt* uc, XP_U16 stringCode )
return result; return result;
} }
/* FIXME: This will always return the same string, ignoring quantity all but
the first time (because of util->userStrings) */
static const XP_UCHAR* static const XP_UCHAR*
and_util_getUserQuantityString( XW_UtilCtxt* uc, XP_U16 stringCode, XP_U16 quantity ) and_util_getUserQuantityString( XW_UtilCtxt* uc, XP_U16 stringCode, XP_U16 quantity )
{ {
LOG_FUNC();
XP_UCHAR* result = ""; XP_UCHAR* result = "";
UTIL_CBK_HEADER("getUserQuantityString", "(II)Ljava/lang/String;" ); UTIL_CBK_HEADER("getUserQuantityString", "(II)Ljava/lang/String;" );
int index = stringCode - 1; /* see LocalizedStrIncludes.h */ int index = stringCode - 1; /* see LocalizedStrIncludes.h */
@ -478,7 +475,6 @@ and_util_getUserQuantityString( XW_UtilCtxt* uc, XP_U16 stringCode, XP_U16 quant
result = ptrs[indx]; result = ptrs[indx];
UTIL_CBK_TAIL(); UTIL_CBK_TAIL();
LOG_RETURNF( "%s", result );
return result; return result;
} }

View file

@ -126,19 +126,14 @@ map_init( MPFORMAL EnvThreadInfo* ti, JNIEnv* env )
static void static void
map_remove( EnvThreadInfo* ti, JNIEnv* env ) map_remove( EnvThreadInfo* ti, JNIEnv* env )
{ {
#ifdef DEBUG
pthread_t self = pthread_self();
#endif
XP_Bool found = false; XP_Bool found = false;
pthread_mutex_lock( &ti->mtxThreads ); pthread_mutex_lock( &ti->mtxThreads );
for ( int ii = 0; !found && ii < ti->nEntries; ++ii ) { for ( int ii = 0; !found && ii < ti->nEntries; ++ii ) {
found = env == ti->entries[ii].env; found = env == ti->entries[ii].env;
if ( found ) { if ( found ) {
/* XP_LOGF( "%s: clearing out %dth entry (thread %x)", __func__, ii, */ XP_ASSERT( pthread_self() == ti->entries[ii].owner );
/* (int)self ); */
ti->entries[ii].env = NULL; ti->entries[ii].env = NULL;
XP_ASSERT( ti->entries[ii].owner = self );
ti->entries[ii].owner = 0; ti->entries[ii].owner = 0;
} }
} }

View file

@ -14,4 +14,12 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
/> />
<CheckBox android:id="@+id/default_check"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/dicts_item_select"
android:layout_marginLeft="20dip"
android:visibility="gone"
/>
</LinearLayout> </LinearLayout>

View file

@ -128,6 +128,10 @@
<string name="key_invite_multi">key_invite_multi</string> <string name="key_invite_multi">key_invite_multi</string>
<string name="key_notagain_enablepublic">key_notagain_enablepublic</string> <string name="key_notagain_enablepublic">key_notagain_enablepublic</string>
<string name="key_na_comms_bt">key_na_comms_bt</string>
<string name="key_na_comms_sms">key_na_comms_sms</string>
<string name="key_na_comms_relay">key_na_comms_relay</string>
<!-- Nor is my email address --> <!-- Nor is my email address -->
<string name="email_author_email">xwords@eehouse.org</string> <string name="email_author_email">xwords@eehouse.org</string>

View file

@ -1170,6 +1170,7 @@
it immediately because an email or messaging app will be it immediately because an email or messaging app will be
launched to send your invitation. --> launched to send your invitation. -->
<string name="newgame_invite">Invite now</string> <string name="newgame_invite">Invite now</string>
<string name="newgame_drop_relay">Drop Relay</string>
<!-- section separator (white-on-gray bar) for third section: <!-- section separator (white-on-gray bar) for third section:
bluetooth games --> bluetooth games -->
@ -1971,6 +1972,10 @@
<!-- --> <!-- -->
<string name="game_list_tmp">Building game summary…</string> <string name="game_list_tmp">Building game summary…</string>
<string name="connstat_net_noaddr">This networked game has no way
to connect and will never be playable.\n\n(It was probably created
from an invitation that didn\'t specify any way of connecting
that your device supports.)</string>
<!-- --> <!-- -->
<string name="connstat_net_fmt">Network status for game connected via <string name="connstat_net_fmt">Network status for game connected via
%1$s:</string> %1$s:</string>
@ -2463,9 +2468,45 @@
<string name="checking_for_fmt">Checking for wordlists in %1$s…</string> <string name="checking_for_fmt">Checking for wordlists in %1$s…</string>
<string name="db_store_done">SD card write complete.</string> <string name="db_store_done">SD card write complete.</string>
<string name="seeking_relay">Connecting to relay…</string>
<string name="no_relay_conn">This game is configured to use the <string name="no_relay_conn">This game is configured to use the
relay for communication but has been unable to connect, either relay (internet) for communication but has been unable to
because of problems with your device\'s internet connection or connect.\n\nPlease try opening the game again later after
because the relay is not running.\n\nPlease try opening the game again conditions have changed.</string>
later.</string>
<string name="drop_relay_warning_fmt">(This game can also connect
via %1$s, so if you\'d like to play the game without a relay
connection you can.)
</string>
<string name="confirm_drop_relay">Are you sure you want to drop this
game\'s ability to communicate via the relay?</string>
<string name="wifi_warning">\u0020For example, you may need to be on
a different WiFi network.</string>
<string name="confirm_drop_relay_bt">Bluetooth only works for nearby
devices.</string>
<string name="confirm_drop_relay_sms">Not all carriers support play
via SMS.</string>
<string name="button_enable">Enable</string>
<string name="not_again_comms_relay">The \"relay\" is a server on
the internet that passes messages between devices that are running
Crosswords. It works any time you have a fully-functional internet
connection, but might have problems on restricted WiFi
networks.</string>
<string name="not_again_comms_sms">Play via SMS uses the same
technology as \"texting\". Though the messages are invisible to you,
your carrier considers them texts, so you want to avoid this feature
unless you have an unlimited texting plan (or budget.) Note that
Android only supports this feature on devices on a GSM carrier,
i.e. every carrier in the world except Verizon and Sprint.</string>
<string name="not_again_comms_bt">Use Bluetooth to play against a
nearby device that\'s \"paired\" with yours.</string>
</resources> </resources>

View file

@ -1008,6 +1008,7 @@
it immediately because an email or messaging app will be it immediately because an email or messaging app will be
launched to send your invitation. --> launched to send your invitation. -->
<string name="newgame_invite">Etivni won</string> <string name="newgame_invite">Etivni won</string>
<string name="newgame_drop_relay">Pord Yaler</string>
<!-- section separator (white-on-gray bar) for third section: <!-- section separator (white-on-gray bar) for third section:
bluetooth games --> bluetooth games -->
<string name="newgame_bt_header">Wen Htooteulb emag</string> <string name="newgame_bt_header">Wen Htooteulb emag</string>
@ -1707,6 +1708,10 @@
<string name="board_menu_dict">Esworb tsildrow</string> <string name="board_menu_dict">Esworb tsildrow</string>
<!-- --> <!-- -->
<string name="game_list_tmp">Gnidliub emag yrammus…</string> <string name="game_list_tmp">Gnidliub emag yrammus…</string>
<string name="connstat_net_noaddr">Siht dekrowten emag sah on yaw
ot tcennoc dna lliw reven eb elbayalp.\n\ntI( saw ylbaborp detaerc
morf na noitativni taht ndid\'t yficeps yna yaw fo gnitcennoc
taht ruoy ecived stroppus.)</string>
<!-- --> <!-- -->
<string name="connstat_net_fmt">Krowten sutats rof emag detcennoc aiv <string name="connstat_net_fmt">Krowten sutats rof emag detcennoc aiv
%1$s:</string> %1$s:</string>
@ -2132,9 +2137,35 @@
<string name="checking_title">Gnikcehc</string> <string name="checking_title">Gnikcehc</string>
<string name="checking_for_fmt">Gnikcehc rof stsildrow ni %1$s…</string> <string name="checking_for_fmt">Gnikcehc rof stsildrow ni %1$s…</string>
<string name="db_store_done">DS drac etirw etelpmoc.</string> <string name="db_store_done">DS drac etirw etelpmoc.</string>
<string name="seeking_relay">Gnitcennoc ot yaler…</string>
<string name="no_relay_conn">Siht emag si derugifnoc ot esu eht <string name="no_relay_conn">Siht emag si derugifnoc ot esu eht
yaler rof noitacinummoc tub sah neeb elbanu ot ,tcennoc rehtie yaler )tenretni( rof noitacinummoc tub sah neeb elbanu ot
esuaceb fo smelborp htiw ruoy ecived\'s tenretni noitcennoc ro tcennoc.\n\nEsaelp yrt gninepo eht emag niaga retal retfa
esuaceb eht yaler si ton gninnur.\n\nEsaelp yrt gninepo eht emag niaga snoitidnoc evah degnahc.</string>
retal.</string> <string name="drop_relay_warning_fmt">sIht( emag nac osla tcennoc
aiv %1$s, os fi uoy\'d ekil ot yalp eht emag tuohtiw a yaler
noitcennoc uoy nac.)
</string>
<string name="confirm_drop_relay">Era uoy erus uoy tnaw ot pord siht
emag\'s ytiliba ot etacinummoc aiv eht ?yaler</string>
<string name="wifi_warning">\u0020Rof ,elpmaxe uoy yam deen ot eb no
a tnereffid IfIw krowten.</string>
<string name="confirm_drop_relay_bt">Htooteulb ylno skrow rof ybraen
secived.</string>
<string name="confirm_drop_relay_sms">Ton lla sreirrac troppus yalp
aiv SMS.</string>
<string name="button_enable">Elbane</string>
<string name="not_again_comms_relay">Eht \"yaler\" si a revres no
eht tenretni taht sessap segassem neewteb secived taht era gninnur
Sdrowssorc. Ti skrow yna emit uoy evah a lanoitcnuf-ylluf tenretni
,noitcennoc tub thgim evah smelborp no detcirtser IfIw
skrowten.</string>
<string name="not_again_comms_sms">Yalp aiv SMS sesu eht emas
ygolonhcet sa \"gnitxet\". Hguoht eht segassem era elbisivni ot ,uoy
ruoy reirrac sredisnoc meht ,stxet os uoy tnaw ot diova siht erutaef
sselnu uoy evah na detimilnu gnitxet nalp ro( tegdub.) Eton taht
Diordna ylno stroppus siht erutaef no secived no a MSG ,reirrac
i.e. yreve reirrac ni eht dlrow tpecxe Nozirev dna Tnirps.</string>
<string name="not_again_comms_bt">Esu Htooteulb ot yalp tsniaga a
ybraen ecived taht\'s \"deriap\" htiw sruoy.</string>
</resources> </resources>

View file

@ -1008,6 +1008,7 @@
it immediately because an email or messaging app will be it immediately because an email or messaging app will be
launched to send your invitation. --> launched to send your invitation. -->
<string name="newgame_invite">INVITE NOW</string> <string name="newgame_invite">INVITE NOW</string>
<string name="newgame_drop_relay">DROP RELAY</string>
<!-- section separator (white-on-gray bar) for third section: <!-- section separator (white-on-gray bar) for third section:
bluetooth games --> bluetooth games -->
<string name="newgame_bt_header">NEW BLUETOOTH GAME</string> <string name="newgame_bt_header">NEW BLUETOOTH GAME</string>
@ -1707,6 +1708,10 @@
<string name="board_menu_dict">BROWSE WORDLIST</string> <string name="board_menu_dict">BROWSE WORDLIST</string>
<!-- --> <!-- -->
<string name="game_list_tmp">BUILDING GAME SUMMARY…</string> <string name="game_list_tmp">BUILDING GAME SUMMARY…</string>
<string name="connstat_net_noaddr">THIS NETWORKED GAME HAS NO WAY
TO CONNECT AND WILL NEVER BE PLAYABLE.\n\n(IT WAS PROBABLY CREATED
FROM AN INVITATION THAT DIDN\'T SPECIFY ANY WAY OF CONNECTING
THAT YOUR DEVICE SUPPORTS.)</string>
<!-- --> <!-- -->
<string name="connstat_net_fmt">NETWORK STATUS FOR GAME CONNECTED VIA <string name="connstat_net_fmt">NETWORK STATUS FOR GAME CONNECTED VIA
%1$s:</string> %1$s:</string>
@ -2132,9 +2137,35 @@
<string name="checking_title">CHECKING</string> <string name="checking_title">CHECKING</string>
<string name="checking_for_fmt">CHECKING FOR WORDLISTS IN %1$s…</string> <string name="checking_for_fmt">CHECKING FOR WORDLISTS IN %1$s…</string>
<string name="db_store_done">SD CARD WRITE COMPLETE.</string> <string name="db_store_done">SD CARD WRITE COMPLETE.</string>
<string name="seeking_relay">CONNECTING TO RELAY…</string>
<string name="no_relay_conn">THIS GAME IS CONFIGURED TO USE THE <string name="no_relay_conn">THIS GAME IS CONFIGURED TO USE THE
RELAY FOR COMMUNICATION BUT HAS BEEN UNABLE TO CONNECT, EITHER RELAY (INTERNET) FOR COMMUNICATION BUT HAS BEEN UNABLE TO
BECAUSE OF PROBLEMS WITH YOUR DEVICE\'S INTERNET CONNECTION OR CONNECT.\n\nPLEASE TRY OPENING THE GAME AGAIN LATER AFTER
BECAUSE THE RELAY IS NOT RUNNING.\n\nPLEASE TRY OPENING THE GAME AGAIN CONDITIONS HAVE CHANGED.</string>
LATER.</string> <string name="drop_relay_warning_fmt">(THIS GAME CAN ALSO CONNECT
VIA %1$s, SO IF YOU\'D LIKE TO PLAY THE GAME WITHOUT A RELAY
CONNECTION YOU CAN.)
</string>
<string name="confirm_drop_relay">ARE YOU SURE YOU WANT TO DROP THIS
GAME\'S ABILITY TO COMMUNICATE VIA THE RELAY?</string>
<string name="wifi_warning">\u0020FOR EXAMPLE, YOU MAY NEED TO BE ON
A DIFFERENT WIFI NETWORK.</string>
<string name="confirm_drop_relay_bt">BLUETOOTH ONLY WORKS FOR NEARBY
DEVICES.</string>
<string name="confirm_drop_relay_sms">NOT ALL CARRIERS SUPPORT PLAY
VIA SMS.</string>
<string name="button_enable">ENABLE</string>
<string name="not_again_comms_relay">THE \"RELAY\" IS A SERVER ON
THE INTERNET THAT PASSES MESSAGES BETWEEN DEVICES THAT ARE RUNNING
CROSSWORDS. IT WORKS ANY TIME YOU HAVE A FULLY-FUNCTIONAL INTERNET
CONNECTION, BUT MIGHT HAVE PROBLEMS ON RESTRICTED WIFI
NETWORKS.</string>
<string name="not_again_comms_sms">PLAY VIA SMS USES THE SAME
TECHNOLOGY AS \"TEXTING\". THOUGH THE MESSAGES ARE INVISIBLE TO YOU,
YOUR CARRIER CONSIDERS THEM TEXTS, SO YOU WANT TO AVOID THIS FEATURE
UNLESS YOU HAVE AN UNLIMITED TEXTING PLAN (OR BUDGET.) NOTE THAT
ANDROID ONLY SUPPORTS THIS FEATURE ON DEVICES ON A GSM CARRIER,
I.E. EVERY CARRIER IN THE WORLD EXCEPT VERIZON AND SPRINT.</string>
<string name="not_again_comms_bt">USE BLUETOOTH TO PLAY AGAINST A
NEARBY DEVICE THAT\'S \"PAIRED\" WITH YOURS.</string>
</resources> </resources>

View file

@ -163,7 +163,8 @@ obtenir une copie avec les mêmes paramètres.</string>
<item quantity="one">Êtes-vous sûr de vouloir effacer la partie <item quantity="one">Êtes-vous sûr de vouloir effacer la partie
sélectionnée ? Cette action ne peut pas être annulée.</item> sélectionnée ? Cette action ne peut pas être annulée.</item>
<item quantity="other">Êtes-vous sûr de vouloir effacer les <item quantity="other">Êtes-vous sûr de vouloir effacer les
%1$d parties sélectionnées ? Cette action ne peut pas être annulée.</item> %1$d parties sélectionnées ? Cette action ne peut pas être
annulée.</item>
</plurals> </plurals>
<!-- Text of confirmation dialog posted when list_item_reset menu <!-- Text of confirmation dialog posted when list_item_reset menu
@ -1405,6 +1406,7 @@ réseau. (Vous pourrez envoyer des invitations plus tard.)</string>
launched to send your invitation. --> launched to send your invitation. -->
<!--<string name="newgame_invite">Invite now</string>--> <!--<string name="newgame_invite">Invite now</string>-->
<string name="newgame_invite">Inviter maintenant</string> <string name="newgame_invite">Inviter maintenant</string>
<string name="newgame_drop_relay">Abandonner le relai</string>
<!-- section separator (white-on-gray bar) for third section: <!-- section separator (white-on-gray bar) for third section:
bluetooth games --> bluetooth games -->
@ -2481,6 +2483,12 @@ illimités ? Annulez si vous n\'êtes pas sûr.</string>
<!--<string name="game_list_tmp">Building game summary…</string>--> <!--<string name="game_list_tmp">Building game summary…</string>-->
<string name="game_list_tmp">Création du résumé de la partie…</string> <string name="game_list_tmp">Création du résumé de la partie…</string>
<string name="connstat_net_noaddr"> Cette partie en réseau n\'a
aucun moyen de se connecter et ne sera jamais jouable.\n\n(Elle a
probablement été créée depuis une invitation qui ne spécifiait
aucun moyen de connexion permis par votre périphérique.)
</string>
<!-- --> <!-- -->
<!--<string name="connstat_net_fmt">Network status for game connected via <!--<string name="connstat_net_fmt">Network status for game connected via
%1$s:</string>--> %1$s:</string>-->
@ -3444,10 +3452,27 @@ pour la langue</string>
<!-- <string name="db_store_done">SD card write complete.</string> --> <!-- <string name="db_store_done">SD card write complete.</string> -->
<string name="db_store_done">Écriture sur la carte SD finie.</string> <string name="db_store_done">Écriture sur la carte SD finie.</string>
<string name="seeking_relay">Connexion au relai…</string>
<string name="no_relay_conn">Cette partie est configurée pour <string name="no_relay_conn">Cette partie est configurée pour
communiquer en utilisant le relai mais n\'a pas pu se connecter, soit communiquer en utilisant le relai (Internet) mais n\'a pas pu se
à cause de problèmes avec la connexion Internet de votre périphérique, connecter.\n\nVeuillez réessayer d\'ouvrir la partie ultérieurement,
soit parce que le relai est hors service.\n\n Veuillez réessayer après que les conditions aient changé.</string>
d\'ouvrir la partie ultérieurement.</string>
<string name="drop_relay_warning_fmt">(Cette partie peut aussi se
connecter par %1$s, donc vous pouvez jouer sans un relai si vous le
souhaitez.) </string>
<string name="confirm_drop_relay">Êtes-vous sûr de vouloir
abandonner la possibilité de communiquer via le relai pour cette
partie ?</string>
<string name="wifi_warning">\u0020Vous pourriez, par exemple,
avoir besoin d\'être sur un réseau Wi-Fi différent.</string>
<string name="confirm_drop_relay_bt">Le Bluetooth ne marche que pour
les périphériques proches.</string>
<string name="confirm_drop_relay_sms">Jouer par SMS n\'est pas
possible avec tous les opérateurs.</string>
</resources> </resources>

View file

@ -1099,7 +1099,7 @@ public class BTService extends XWService {
private DataOutputStream connect( BluetoothSocket socket, BTCmd cmd ) private DataOutputStream connect( BluetoothSocket socket, BTCmd cmd )
{ {
String name = socket.getRemoteDevice().getName(); String name = socket.getRemoteDevice().getName();
DbgUtils.logf( "connecting to %s to send cmd %s", name, cmd.toString() ); // DbgUtils.logf( "connecting to %s to send cmd %s", name, cmd.toString() );
// Docs say always call cancelDiscovery before trying to connect // Docs say always call cancelDiscovery before trying to connect
m_adapter.cancelDiscovery(); m_adapter.cancelDiscovery();
@ -1112,7 +1112,7 @@ public class BTService extends XWService {
DbgUtils.logf( "connect() to %s successful", name ); DbgUtils.logf( "connect() to %s successful", name );
} catch ( IOException ioe ) { } catch ( IOException ioe ) {
dos = null; dos = null;
DbgUtils.logf( "connect() to %s failed", name ); DbgUtils.logf( "BTService.connect() to %s failed", name );
// logIOE( ioe ); // logIOE( ioe );
} }
return dos; return dos;

View file

@ -291,10 +291,7 @@ public class BoardDelegate extends DelegateBase
lstnr = new OnClickListener() { lstnr = new OnClickListener() {
public void onClick( DialogInterface dlg, public void onClick( DialogInterface dlg,
int whichButton ) { int whichButton ) {
deleteAndClose();
waitCloseGame( false );
GameUtils.deleteGame( m_activity, m_rowid, false );
finish();
} }
}; };
ab.setNegativeButton( R.string.button_delete, lstnr ); ab.setNegativeButton( R.string.button_delete, lstnr );
@ -432,13 +429,16 @@ public class BoardDelegate extends DelegateBase
.setNegativeButton( R.string.button_no, null ) .setNegativeButton( R.string.button_no, null )
.create(); .create();
break; break;
case DLG_NOINVITE:
Assert.assertFalse( m_relayConnected );
case DLG_INVITE: case DLG_INVITE:
lstnr = new OnClickListener() { lstnr = new OnClickListener() {
public void onClick( DialogInterface dialog, public void onClick( DialogInterface dialog,
int item ) { int item ) {
if ( m_relayConnected ||
! m_connTypes.contains(CommsConnType.COMMS_CONN_RELAY) ) {
showInviteChoicesThen( Action.LAUNCH_INVITE_ACTION ); showInviteChoicesThen( Action.LAUNCH_INVITE_ACTION );
} else {
askDropRelay();
}
} }
}; };
OnClickListener lstnr2 = new OnClickListener() { OnClickListener lstnr2 = new OnClickListener() {
@ -449,7 +449,7 @@ public class BoardDelegate extends DelegateBase
}; };
dialog = ab.setTitle( "foo" ) dialog = ab.setTitle( "foo" )
.setMessage( "" ) .setMessage( "" )
.setPositiveButton( R.string.newgame_invite, lstnr ) .setPositiveButton( "", lstnr )
.setNegativeButton( R.string.button_close_game, lstnr2 ) .setNegativeButton( R.string.button_close_game, lstnr2 )
.setOnCancelListener( new OnCancelListener() { .setOnCancelListener( new OnCancelListener() {
public void onCancel( DialogInterface dialog ) { public void onCancel( DialogInterface dialog ) {
@ -476,20 +476,39 @@ public class BoardDelegate extends DelegateBase
{ {
switch( dlgID ) { switch( dlgID ) {
case DLG_INVITE: case DLG_INVITE:
case DLG_NOINVITE:
AlertDialog ad = (AlertDialog)dialog; AlertDialog ad = (AlertDialog)dialog;
String message; String message;
int titleID = R.string.info_title;; int titleID;
boolean nukeButton = false; boolean nukeButton = false;
int buttonTxt = R.string.newgame_invite;
if ( m_summary.hasRematchInfo() ) { if ( m_summary.hasRematchInfo() ) {
titleID = R.string.info_title;;
message = getString( R.string.rematch_msg ); message = getString( R.string.rematch_msg );
nukeButton = true; nukeButton = true;
} else if ( DlgID.DLG_NOINVITE == dlgID ) { } else {
if ( !m_relayConnected ) {
titleID = R.string.seeking_relay;
// If relay is only means, don't allow at all
boolean relayOnly = 1 >= m_connTypes.size();
nukeButton = relayOnly;
message = getString( R.string.no_relay_conn ); message = getString( R.string.no_relay_conn );
nukeButton = true; if ( NetStateCache.netAvail( m_activity )
&& NetStateCache.onWifi() ) {
message += getString( R.string.wifi_warning );
}
if ( !relayOnly ) {
CommsConnTypeSet without = (CommsConnTypeSet)
m_connTypes.clone();
without.remove( CommsConnType.COMMS_CONN_RELAY );
message += "\n\n"
+ getString( R.string.drop_relay_warning_fmt,
without.toString( m_activity ) );
buttonTxt = R.string.newgame_drop_relay;
}
} else { } else {
titleID = R.string.waiting_title; titleID = R.string.waiting_title;
message = getQuantityString( R.plurals.invite_msg_fmt, m_nMissing, m_nMissing ); message = getQuantityString( R.plurals.invite_msg_fmt,
m_nMissing, m_nMissing );
String ps = null; String ps = null;
if ( m_nMissing > 1 ) { if ( m_nMissing > 1 ) {
@ -506,11 +525,16 @@ public class BoardDelegate extends DelegateBase
message += "\n\n" + getString( R.string.invite_stays ); message += "\n\n" + getString( R.string.invite_stays );
} }
if ( nukeButton ) {
ad.getButton( AlertDialog.BUTTON_POSITIVE ).setVisibility( View.GONE );
} }
ad.setMessage( message ); ad.setMessage( message );
ad.setTitle( titleID ); ad.setTitle( titleID );
Button posButton = ad.getButton( AlertDialog.BUTTON_POSITIVE );
posButton.setVisibility( nukeButton ? View.GONE : View.VISIBLE );
if ( !nukeButton ) {
posButton.setText( buttonTxt );
}
break; break;
default: default:
super.prepareDialog( dlgID, dialog ); super.prepareDialog( dlgID, dialog );
@ -636,11 +660,8 @@ public class BoardDelegate extends DelegateBase
// onResume -- meaning m_gi etc are still null. // onResume -- meaning m_gi etc are still null.
m_missingDevs = data.getStringArrayExtra( InviteDelegate.DEVS ); m_missingDevs = data.getStringArrayExtra( InviteDelegate.DEVS );
m_missingCounts = data.getIntArrayExtra( InviteDelegate.COUNTS ); m_missingCounts = data.getIntArrayExtra( InviteDelegate.COUNTS );
if ( BT_INVITE_RESULT == requestCode ) { m_missingMeans = (BT_INVITE_RESULT == requestCode)
m_missingMeans = InviteMeans.BLUETOOTH; ? InviteMeans.BLUETOOTH : InviteMeans.SMS;
} else {
m_missingMeans = InviteMeans.SMS;
}
break; break;
} }
} }
@ -659,9 +680,7 @@ public class BoardDelegate extends DelegateBase
setBackgroundColor(); setBackgroundColor();
setKeepScreenOn(); setKeepScreenOn();
} else if ( ! isFinishing() ) { } else if ( ! isFinishing() ) {
if ( !m_relayConnected ) { if ( !m_relayConnected || 0 < m_nMissing ) {
showDialog( DlgID.DLG_NOINVITE );
} else if ( 0 < m_nMissing ) {
showDialog( DlgID.DLG_INVITE ); showDialog( DlgID.DLG_INVITE );
} }
} }
@ -988,6 +1007,12 @@ public class BoardDelegate extends DelegateBase
case NFC_TO_SELF: case NFC_TO_SELF:
GamesListDelegate.sendNFCToSelf( m_activity, makeNFCMessage() ); GamesListDelegate.sendNFCToSelf( m_activity, makeNFCMessage() );
break; break;
case DROP_RELAY_ACTION:
dropRelayAndRestart();
break;
case DELETE_AND_EXIT:
deleteAndClose();
break;
default: default:
handled = false; handled = false;
} }
@ -1027,6 +1052,9 @@ public class BoardDelegate extends DelegateBase
case EMAIL: case EMAIL:
NetLaunchInfo nli = new NetLaunchInfo( m_summary, m_gi, 1, NetLaunchInfo nli = new NetLaunchInfo( m_summary, m_gi, 1,
1 + m_nGuestDevs ); 1 + m_nGuestDevs );
if ( !m_relayConnected ) {
nli.removeAddress( CommsConnType.COMMS_CONN_RELAY );
}
GameUtils.launchEmailInviteActivity( m_activity, nli ); GameUtils.launchEmailInviteActivity( m_activity, nli );
break; break;
default: default:
@ -1262,15 +1290,17 @@ public class BoardDelegate extends DelegateBase
public void onStatusClicked() public void onStatusClicked()
{ {
final String msg = ConnStatusHandler.getStatusText( m_activity, m_connTypes ); final String msg = ConnStatusHandler.getStatusText( m_activity, m_connTypes );
if ( null != msg ) {
post( new Runnable() { post( new Runnable() {
public void run() { public void run() {
if ( null == msg ) {
askNoAddrsDelete();
} else {
m_dlgBytes = msg; m_dlgBytes = msg;
m_dlgTitle = R.string.info_title; m_dlgTitle = R.string.info_title;
showDialog( DlgID.DLG_CONNSTAT ); showDialog( DlgID.DLG_CONNSTAT );
} }
} );
} }
} );
} }
public Handler getHandler() public Handler getHandler()
@ -1278,6 +1308,43 @@ public class BoardDelegate extends DelegateBase
return m_handler; return m_handler;
} }
private void deleteAndClose()
{
waitCloseGame( false );
GameUtils.deleteGame( m_activity, m_rowid, false );
finish();
}
private void askNoAddrsDelete()
{
showConfirmThen( R.string.connstat_net_noaddr,
R.string.list_item_delete,
Action.DELETE_AND_EXIT );
}
private void askDropRelay()
{
String msg = getString( R.string.confirm_drop_relay );
if ( m_connTypes.contains(CommsConnType.COMMS_CONN_BT) ) {
msg += " " + getString( R.string.confirm_drop_relay_bt );
}
if ( m_connTypes.contains(CommsConnType.COMMS_CONN_SMS) ) {
msg += " " + getString( R.string.confirm_drop_relay_sms );
}
showConfirmThen( msg, Action.DROP_RELAY_ACTION );
}
private void dropRelayAndRestart() {
CommsAddrRec addr = new CommsAddrRec();
XwJNI.comms_getAddr( m_jniGamePtr, addr );
addr.remove( CommsConnType.COMMS_CONN_RELAY );
XwJNI.comms_setAddr( m_jniGamePtr, addr );
finish();
GameUtils.launchGame( m_activity, m_rowid, m_haveInvited );
}
private void setGotGameDict( String getDict ) private void setGotGameDict( String getDict )
{ {
m_jniThread.setSaveDict( getDict ); m_jniThread.setSaveDict( getDict );
@ -1367,9 +1434,7 @@ public class BoardDelegate extends DelegateBase
private void handleConndMessage( String room, int devOrder, // <- hostID private void handleConndMessage( String room, int devOrder, // <- hostID
boolean allHere, int nMissing ) boolean allHere, int nMissing )
{ {
DbgUtils.logf( "BoardDelegate.handleConndMessage(): nMissing = %d", nMissing ); dismissInviteAlert( nMissing, true );
dismissInviteAlerts( nMissing, true );
int naMsg = 0; int naMsg = 0;
int naKey = 0; int naKey = 0;
@ -1714,21 +1779,21 @@ public class BoardDelegate extends DelegateBase
{ {
m_connTypes = connTypes; m_connTypes = connTypes;
Assert.assertTrue( isServer || 0 == nMissing ); Assert.assertTrue( isServer || 0 == nMissing );
DbgUtils.logf( "BoardDelegate.informMissing(isServer=%b, nDevs=%d, nMissing=%d)", // DbgUtils.logf( "BoardDelegate.informMissing(isServer=%b, nDevs=%d, nMissing=%d)",
isServer, nDevs, nMissing ); // isServer, nDevs, nMissing );
m_nGuestDevs = nDevs; m_nGuestDevs = nDevs;
// If we might have put up an alert earlier, take it down // If we might have put up an alert earlier, take it down
dismissInviteAlerts( nMissing, m_relayConnected ); dismissInviteAlert( nMissing, m_relayConnected );
m_nMissing = nMissing; // will be 0 unless isServer is true m_nMissing = nMissing; // will be 0 unless isServer is true
final DlgID dlgID = if ( null != connTypes && 0 == connTypes.size() ) {
m_relayConnected ? DlgID.DLG_INVITE : DlgID.DLG_NOINVITE; askNoAddrsDelete();
if ( 0 < nMissing && isServer && !m_haveInvited ) { } else if ( 0 < nMissing && isServer && !m_haveInvited ) {
post( new Runnable() { post( new Runnable() {
public void run() { public void run() {
showDialog( dlgID ); showDialog( DlgID.DLG_INVITE );
} }
} ); } );
} }
@ -1875,7 +1940,6 @@ public class BoardDelegate extends DelegateBase
m_gi = new CurGameInfo( m_activity ); m_gi = new CurGameInfo( m_activity );
m_gi.setName( gameName ); m_gi.setName( gameName );
XwJNI.gi_from_stream( m_gi, stream ); XwJNI.gi_from_stream( m_gi, stream );
DbgUtils.logf( "BoardDelegate:after loadGame: gi.nPlayers: %d", m_gi.nPlayers );
String langName = m_gi.langName(); String langName = m_gi.langName();
m_summary = DBUtils.getSummary( m_activity, m_gameLock ); m_summary = DBUtils.getSummary( m_activity, m_gameLock );
@ -2029,15 +2093,14 @@ public class BoardDelegate extends DelegateBase
} }
} }
private void dismissInviteAlerts( final int nMissing, final boolean connected ) private void dismissInviteAlert( final int nMissing, final boolean connected )
{ {
runOnUiThread( new Runnable() { runOnUiThread( new Runnable() {
public void run() { public void run() {
if ( !m_relayConnected && connected ) { if ( !m_relayConnected && connected ) {
m_relayConnected = true; m_relayConnected = true;
dismissDialog( DlgID.DLG_NOINVITE );
} }
if ( 0 == nMissing ) { if ( 0 == nMissing || m_relayConnected ) {
dismissDialog( DlgID.DLG_INVITE ); dismissDialog( DlgID.DLG_INVITE );
} }
} }
@ -2278,6 +2341,10 @@ public class BoardDelegate extends DelegateBase
int forceChannel = ii + m_nGuestDevs + 1; int forceChannel = ii + m_nGuestDevs + 1;
NetLaunchInfo nli = new NetLaunchInfo( m_summary, m_gi, NetLaunchInfo nli = new NetLaunchInfo( m_summary, m_gi,
nPlayers, forceChannel ); nPlayers, forceChannel );
if ( !m_relayConnected ) {
nli.removeAddress( CommsConnType.COMMS_CONN_RELAY );
}
switch ( m_missingMeans ) { switch ( m_missingMeans ) {
case BLUETOOTH: case BLUETOOTH:
if ( ! m_progressShown ) { if ( ! m_progressShown ) {
@ -2424,6 +2491,7 @@ public class BoardDelegate extends DelegateBase
private void doRematch() private void doRematch()
{ {
if ( XWApp.REMATCH_SUPPORTED ) {
String phone = null; String phone = null;
String btAddr = null; String btAddr = null;
String relayID = null; String relayID = null;
@ -2453,10 +2521,11 @@ public class BoardDelegate extends DelegateBase
finish(); finish();
} }
} }
}
private void tryRematchInvites() private void tryRematchInvites()
{ {
if ( !m_rematchInvitesSent ) { if ( XWApp.REMATCH_SUPPORTED && !m_rematchInvitesSent ) {
m_rematchInvitesSent = true; m_rematchInvitesSent = true;
Assert.assertNotNull( m_summary ); Assert.assertNotNull( m_summary );

View file

@ -453,8 +453,6 @@ public class CommsTransport implements TransportProcs,
Assert.fail(); Assert.fail();
break; break;
} }
DbgUtils.logf( "sendForAddr(addr=%s)=>%d", conType.toString(),
nSent );
return nSent; return nSent;
} }

View file

@ -310,15 +310,7 @@ public class ConnStatusHandler {
// Do the background coloring. Top quarter first // Do the background coloring. Top quarter first
rect.bottom = rect.top + quarterHeight; rect.bottom = rect.top + quarterHeight;
record = newestSuccess( connTypes, false ); drawQuarter( canvas, res, rect, connTypes, enabled, false );
s_fillPaint.setColor( isSolo || (enabled && record.successNewer)
? GREEN : RED );
canvas.drawRect( rect, s_fillPaint );
if ( !isSolo ) {
int arrowID = s_showSuccesses[SUCCESS_OUT]?
R.drawable.out_arrow_active : R.drawable.out_arrow;
drawIn( canvas, res, arrowID, rect );
}
// paint the middle two quarters black to give the icon a // paint the middle two quarters black to give the icon a
// clear background // clear background
@ -330,15 +322,7 @@ public class ConnStatusHandler {
// bottom quarter // bottom quarter
rect.top = rect.bottom; rect.top = rect.bottom;
rect.bottom = rect.top + quarterHeight; rect.bottom = rect.top + quarterHeight;
record = newestSuccess( connTypes, true ); drawQuarter( canvas, res, rect, connTypes, enabled, true );
s_fillPaint.setColor( isSolo || (enabled && record.successNewer)
? GREEN : RED );
canvas.drawRect( rect, s_fillPaint );
if ( !isSolo ) {
int arrowID = s_showSuccesses[SUCCESS_IN]?
R.drawable.in_arrow_active : R.drawable.in_arrow;
drawIn( canvas, res, arrowID, rect );
}
rect.top = saveTop; rect.top = saveTop;
} }
@ -361,6 +345,26 @@ public class ConnStatusHandler {
} }
} }
private static void drawQuarter( Canvas canvas, Resources res, Rect rect,
CommsConnTypeSet connTypes,
boolean enabled, boolean isIn )
{
enabled = enabled && null != newestSuccess( connTypes, isIn );
s_fillPaint.setColor( enabled ? GREEN : RED );
canvas.drawRect( rect, s_fillPaint );
int arrowID;
boolean showSuccesses = s_showSuccesses[isIn? SUCCESS_IN : SUCCESS_OUT];
if ( isIn ) {
arrowID = showSuccesses ?
R.drawable.in_arrow_active : R.drawable.in_arrow;
} else {
arrowID = showSuccesses ?
R.drawable.out_arrow_active : R.drawable.out_arrow;
}
drawIn( canvas, res, arrowID, rect );
}
// This gets rid of lint warning, but I don't like it as it // This gets rid of lint warning, but I don't like it as it
// effects the whole method. // effects the whole method.
// @SuppressWarnings("unchecked") // @SuppressWarnings("unchecked")
@ -466,11 +470,13 @@ public class ConnStatusHandler {
while ( iter.hasNext() ) { while ( iter.hasNext() ) {
CommsConnType connType = iter.next(); CommsConnType connType = iter.next();
SuccessRecord record = recordFor( connType, isIn ); SuccessRecord record = recordFor( connType, isIn );
if ( record.successNewer ) {
if ( null == result || result.lastSuccess < record.lastSuccess ) { if ( null == result || result.lastSuccess < record.lastSuccess ) {
result = record; result = record;
} }
} }
} }
}
return result; return result;
} }
@ -489,7 +495,7 @@ public class ConnStatusHandler {
private static void doSave( Context context ) private static void doSave( Context context )
{ {
synchronized( s_lockObj ) { synchronized( s_lockObj ) {
DbgUtils.logf( "ConnStatusHandler:doSave() doing save" ); // DbgUtils.logf( "ConnStatusHandler:doSave() doing save" );
ByteArrayOutputStream bas ByteArrayOutputStream bas
= new ByteArrayOutputStream(); = new ByteArrayOutputStream();
try { try {
@ -529,7 +535,9 @@ public class ConnStatusHandler {
break; break;
case COMMS_CONN_BT: case COMMS_CONN_BT:
result = XWApp.BTSUPPORTED && BTService.BTEnabled() result = XWApp.BTSUPPORTED && BTService.BTEnabled()
&& !getAirplaneModeOn( context ); && BTService.BTEnabled();
// No: we can be in airplane mode but with BT turned on manually.
//!getAirplaneModeOn( context );
break; break;
case COMMS_CONN_RELAY: case COMMS_CONN_RELAY:
result = NetStateCache.netAvail( context ); result = NetStateCache.netAvail( context );

View file

@ -33,8 +33,11 @@ import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnTypeSet; import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnTypeSet;
import org.eehouse.android.xw4.loc.LocUtils; import org.eehouse.android.xw4.loc.LocUtils;
import junit.framework.Assert;
public class ConnViaViewLayout extends LinearLayout { public class ConnViaViewLayout extends LinearLayout {
private CommsConnTypeSet m_curSet; private CommsConnTypeSet m_curSet;
private DlgDelegate.HasDlgDelegate m_dlgDlgt;
public interface CheckEnabledWarner { public interface CheckEnabledWarner {
public void warnDisabled( CommsConnType typ ); public void warnDisabled( CommsConnType typ );
@ -52,7 +55,8 @@ public class ConnViaViewLayout extends LinearLayout {
protected void configure( CommsConnTypeSet types, protected void configure( CommsConnTypeSet types,
CheckEnabledWarner cew, CheckEnabledWarner cew,
SetEmptyWarner sew ) SetEmptyWarner sew,
DlgDelegate.HasDlgDelegate dlgDlgt )
{ {
m_curSet = (CommsConnTypeSet)types.clone(); m_curSet = (CommsConnTypeSet)types.clone();
@ -60,6 +64,7 @@ public class ConnViaViewLayout extends LinearLayout {
m_disabledWarner = cew; m_disabledWarner = cew;
m_emptyWarner = sew; m_emptyWarner = sew;
m_dlgDlgt = dlgDlgt;
} }
protected CommsConnTypeSet getTypes() protected CommsConnTypeSet getTypes()
@ -88,6 +93,7 @@ public class ConnViaViewLayout extends LinearLayout {
public void onCheckedChanged( CompoundButton buttonView, public void onCheckedChanged( CompoundButton buttonView,
boolean isChecked ) { boolean isChecked ) {
if ( isChecked ) { if ( isChecked ) {
showNotAgainTypeTip( typf );
enabledElseWarn( typf ); enabledElseWarn( typf );
m_curSet.add( typf ); m_curSet.add( typf );
} else { } else {
@ -117,4 +123,32 @@ public class ConnViaViewLayout extends LinearLayout {
m_disabledWarner.warnDisabled( typ ); m_disabledWarner.warnDisabled( typ );
} }
} }
private void showNotAgainTypeTip( CommsConnType typ )
{
if ( null != m_dlgDlgt ) {
int keyID = 0;
int msgID = 0;
switch( typ ) {
case COMMS_CONN_RELAY:
msgID = R.string.not_again_comms_relay;
keyID = R.string.key_na_comms_relay;
break;
case COMMS_CONN_SMS:
msgID = R.string.not_again_comms_sms;
keyID = R.string.key_na_comms_sms;
break;
case COMMS_CONN_BT:
msgID = R.string.not_again_comms_bt;
keyID = R.string.key_na_comms_bt;
break;
default:
Assert.fail();
break;
}
m_dlgDlgt.showNotAgainDlgThen( msgID, keyID,
DlgDelegate.Action.SKIP_CALLBACK );
}
}
} }

View file

@ -60,7 +60,6 @@ public class DBHelper extends SQLiteOpenHelper {
public static final String GAMEID = "GAMEID"; public static final String GAMEID = "GAMEID";
public static final String REMOTEDEVS = "REMOTEDEVS"; public static final String REMOTEDEVS = "REMOTEDEVS";
public static final String EXTRAS = "EXTRAS"; public static final String EXTRAS = "EXTRAS";
public static final String JSON_EXTRAS = "JSON_EXTRAS";
public static final String DICTLANG = "DICTLANG"; public static final String DICTLANG = "DICTLANG";
public static final String DICTLIST = "DICTLIST"; public static final String DICTLIST = "DICTLIST";
public static final String HASMSGS = "HASMSGS"; public static final String HASMSGS = "HASMSGS";

View file

@ -373,6 +373,7 @@ public class DBUtils {
public static void addRematchInfo( Context context, long rowid, String btAddr, public static void addRematchInfo( Context context, long rowid, String btAddr,
String phone, String relayID ) String phone, String relayID )
{ {
if ( XWApp.REMATCH_SUPPORTED ) {
GameLock lock = new GameLock( rowid, true ).lock(); GameLock lock = new GameLock( rowid, true ).lock();
GameSummary summary = getSummary( context, lock ); GameSummary summary = getSummary( context, lock );
if ( null != btAddr ) { if ( null != btAddr ) {
@ -387,6 +388,7 @@ public class DBUtils {
saveSummary( context, lock, summary ); saveSummary( context, lock, summary );
lock.unlock(); lock.unlock();
} }
}
public static int countGamesUsingLang( Context context, int lang ) public static int countGamesUsingLang( Context context, int lang )
{ {
@ -570,9 +572,10 @@ public class DBUtils {
long rowid = cursor.getLong( indx1 ); long rowid = cursor.getLong( indx1 );
CommsConnTypeSet typs = new CommsConnTypeSet( cursor.getInt(indx2) ); CommsConnTypeSet typs = new CommsConnTypeSet( cursor.getInt(indx2) );
// Better have an address if has pending sends // Better have an address if has pending sends
Assert.assertTrue( 0 < typs.size() ); if ( 0 < typs.size() ) {
result.put( rowid, typs ); result.put( rowid, typs );
} }
}
cursor.close(); cursor.close();
db.close(); db.close();
} }
@ -718,7 +721,7 @@ public class DBUtils {
cursor.close(); cursor.close();
db.close(); db.close();
} }
DbgUtils.logf( "getMostRecentCreate(%d) => %H", gameID, result );
return result; return result;
} }
@ -763,7 +766,6 @@ public class DBUtils {
long[][] rowIDss = new long[1][]; long[][] rowIDss = new long[1][];
String[] relayIDs = getRelayIDs( context, rowIDss ); String[] relayIDs = getRelayIDs( context, rowIDss );
boolean result = null != relayIDs && 0 < relayIDs.length; boolean result = null != relayIDs && 0 < relayIDs.length;
DbgUtils.logf( "haveRelayGames() => %b", result );
return result; return result;
} }

View file

@ -525,7 +525,10 @@ public class DelegateBase implements DlgClickNotify,
fmtId = R.string.app_not_found_fmt; fmtId = R.string.app_not_found_fmt;
break; break;
default: default:
DbgUtils.logf( "DelegateBase.eventOccurred(event=%s) (DROPPED)", event.toString() ); if ( BuildConfig.DEBUG ) {
DbgUtils.logf( "DelegateBase.eventOccurred(event=%s) (DROPPED)",
event.toString() );
}
} }
if ( 0 != fmtId ) { if ( 0 != fmtId ) {

View file

@ -1135,11 +1135,11 @@ public class DictsDelegate extends ListDelegateBase
// parse less data // parse less data
String name = null; String name = null;
String proc = String.format( "listDicts?lc=%s", m_lc ); String proc = String.format( "listDicts?lc=%s", m_lc );
HttpPost post = UpdateCheckReceiver.makePost( m_context, proc ); HttpPost post = NetUtils.makePost( m_context, proc );
if ( null != post ) { if ( null != post ) {
JSONObject theOne = null; JSONObject theOne = null;
String langName = null; String langName = null;
String json = UpdateCheckReceiver.runPost( post, new JSONObject() ); String json = NetUtils.runPost( post, new JSONObject() );
try { try {
JSONObject obj = new JSONObject( json ); JSONObject obj = new JSONObject( json );
JSONArray langs = obj.optJSONArray( "langs" ); JSONArray langs = obj.optJSONArray( "langs" );
@ -1214,9 +1214,9 @@ public class DictsDelegate extends ListDelegateBase
public Boolean doInBackground( Void... unused ) public Boolean doInBackground( Void... unused )
{ {
boolean success = false; boolean success = false;
HttpPost post = UpdateCheckReceiver.makePost( m_context, "listDicts" ); HttpPost post = NetUtils.makePost( m_context, "listDicts" );
if ( null != post ) { if ( null != post ) {
String json = UpdateCheckReceiver.runPost( post, new JSONObject() ); String json = NetUtils.runPost( post, new JSONObject() );
if ( !isCancelled() ) { if ( !isCancelled() ) {
if ( null != json ) { if ( null != json ) {
post( new Runnable() { post( new Runnable() {

View file

@ -31,10 +31,13 @@ import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.view.View; import android.view.View;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.AdapterView;
import android.widget.Button; import android.widget.Button;
import android.widget.Spinner; import android.widget.Spinner;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import java.text.DateFormat; import java.text.DateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
@ -83,6 +86,7 @@ public class DlgDelegate {
SMS_CONFIG_ACTION, SMS_CONFIG_ACTION,
BUTTON_BROWSEALL_ACTION, BUTTON_BROWSEALL_ACTION,
NFC_TO_SELF, NFC_TO_SELF,
DROP_RELAY_ACTION,
// Dict Browser // Dict Browser
FINISH_ACTION, FINISH_ACTION,
@ -194,8 +198,7 @@ public class DlgDelegate {
protected void showDialog( DlgID dlgID ) protected void showDialog( DlgID dlgID )
{ {
if ( !m_activity.isFinishing() ) { if ( !m_activity.isFinishing() ) {
int id = dlgID.ordinal(); m_activity.showDialog( dlgID.ordinal() );
m_activity.showDialog( id );
} }
} }
@ -239,6 +242,9 @@ public class DlgDelegate {
case INVITE_CHOICES_THEN: case INVITE_CHOICES_THEN:
prepareInviteChoicesDialog( dialog ); prepareInviteChoicesDialog( dialog );
break; break;
case DIALOG_ENABLESMS:
prepareEnableSMSDialog( dialog );
break;
} }
} }
@ -691,6 +697,7 @@ public class DlgDelegate {
Spinner reasons = (Spinner) Spinner reasons = (Spinner)
layout.findViewById( R.id.confirm_sms_reasons ); layout.findViewById( R.id.confirm_sms_reasons );
boolean enabled = 0 < reasons.getSelectedItemPosition(); boolean enabled = 0 < reasons.getSelectedItemPosition();
Assert.assertTrue( enabled );
Object[] params = { new Boolean(enabled), }; Object[] params = { new Boolean(enabled), };
m_clickCallback.dlgButtonClicked( state.m_action, m_clickCallback.dlgButtonClicked( state.m_action,
AlertDialog.BUTTON_POSITIVE, AlertDialog.BUTTON_POSITIVE,
@ -701,12 +708,39 @@ public class DlgDelegate {
Dialog dialog = LocUtils.makeAlertBuilder( m_activity ) Dialog dialog = LocUtils.makeAlertBuilder( m_activity )
.setTitle( R.string.confirm_sms_title ) .setTitle( R.string.confirm_sms_title )
.setView( layout ) .setView( layout )
.setPositiveButton( android.R.string.ok, lstnr ) .setPositiveButton( R.string.button_enable, lstnr )
.setNegativeButton( android.R.string.cancel, null )
.create(); .create();
Utils.setRemoveOnDismiss( m_activity, dialog, dlgID ); Utils.setRemoveOnDismiss( m_activity, dialog, dlgID );
return dialog; return dialog;
} }
private void checkEnableButton( Dialog dialog, Spinner reasons )
{
boolean enabled = 0 < reasons.getSelectedItemPosition();
AlertDialog adlg = (AlertDialog)dialog;
Button button = adlg.getButton( AlertDialog.BUTTON_POSITIVE );
button.setEnabled( enabled );
}
private void prepareEnableSMSDialog( final Dialog dialog )
{
final Spinner reasons = (Spinner)
dialog.findViewById( R.id.confirm_sms_reasons );
OnItemSelectedListener onItemSel = new OnItemSelectedListener() {
public void onItemSelected( AdapterView<?> parent, View view,
int position, long id )
{
checkEnableButton( dialog, reasons );
}
public void onNothingSelected( AdapterView<?> parent ) {}
};
reasons.setOnItemSelectedListener( onItemSel );
checkEnableButton( dialog, reasons );
}
private OnClickListener mkCallbackClickListener( final DlgState state, private OnClickListener mkCallbackClickListener( final DlgState state,
final NotAgainView naView ) final NotAgainView naView )
{ {

View file

@ -35,7 +35,6 @@ public enum DlgID {
, DLG_DELETED , DLG_DELETED
, DLG_DICTGONE , DLG_DICTGONE
, DLG_INVITE , DLG_INVITE
, DLG_NOINVITE
, DLG_OKONLY , DLG_OKONLY
, ENABLE_NFC , ENABLE_NFC
, FORCE_REMOTE , FORCE_REMOTE

View file

@ -67,7 +67,6 @@ public class DwnldDelegate extends ListDelegateBase {
public interface OnGotLcDictListener { public interface OnGotLcDictListener {
void gotDictInfo( boolean success, String lc, String name ); void gotDictInfo( boolean success, String lc, String name );
} }
public DwnldDelegate( ListDelegator delegator, Bundle savedInstanceState ) public DwnldDelegate( ListDelegator delegator, Bundle savedInstanceState )

View file

@ -201,6 +201,8 @@ public class ExpiringDelegate {
m_pct = (int)((100 * passed) / INTERVAL_SECS); m_pct = (int)((100 * passed) / INTERVAL_SECS);
if ( m_pct > 100 ) { if ( m_pct > 100 ) {
m_pct = 100; m_pct = 100;
} else if ( m_pct < 0 ) {
m_pct = 0;
} else if ( null != m_handler ) { } else if ( null != m_handler ) {
long onePct = INTERVAL_SECS / 100; long onePct = INTERVAL_SECS / 100;
long lastStart = m_startSecs + (onePct * m_pct); long lastStart = m_startSecs + (onePct * m_pct);

View file

@ -101,8 +101,15 @@ public class GCMIntentService extends GCMBaseIntentService {
if ( null != value ) { if ( null != value ) {
String title = intent.getStringExtra( "title" ); String title = intent.getStringExtra( "title" );
if ( null != title ) { if ( null != title ) {
String teaser = intent.getStringExtra( "teaser" );
if ( null == teaser ) {
teaser = value;
}
Intent alertIntent = GamesListDelegate
.makeAlertIntent( this, value );
int code = value.hashCode() ^ title.hashCode(); int code = value.hashCode() ^ title.hashCode();
Utils.postNotification( context, null, title, value, code ); Utils.postNotification( context, alertIntent, title,
teaser, code );
} }
} }
} }

View file

@ -24,12 +24,10 @@ import android.os.Bundle;
public class GameConfigActivity extends XWActivity { public class GameConfigActivity extends XWActivity {
private GameConfigDelegate m_dlgt;
@Override @Override
public void onCreate( Bundle savedInstanceState ) public void onCreate( Bundle savedInstanceState )
{ {
m_dlgt = new GameConfigDelegate( this, savedInstanceState ); super.onCreate( savedInstanceState,
super.onCreate( savedInstanceState, m_dlgt ); new GameConfigDelegate( this, savedInstanceState ) );
} // onCreate } // onCreate
} }

View file

@ -285,11 +285,18 @@ public class GameConfigDelegate extends DelegateBase
LinearLayout layout = (LinearLayout)inflate( R.layout.conn_types_display ); LinearLayout layout = (LinearLayout)inflate( R.layout.conn_types_display );
final ConnViaViewLayout items = (ConnViaViewLayout) final ConnViaViewLayout items = (ConnViaViewLayout)
layout.findViewById( R.id.conn_types ); layout.findViewById( R.id.conn_types );
final CheckBox cb = (CheckBox)layout
.findViewById(R.id.default_check);
cb.setVisibility( View.VISIBLE );
final DialogInterface.OnClickListener lstnr = final DialogInterface.OnClickListener lstnr =
new DialogInterface.OnClickListener() { new DialogInterface.OnClickListener() {
public void onClick( DialogInterface dlg, int button ) { public void onClick( DialogInterface dlg, int button ) {
m_conTypes = items.getTypes(); m_conTypes = items.getTypes();
if ( cb.isChecked()) {
XWPrefs.setAddrTypes( m_activity, m_conTypes );
}
m_car.populate( m_activity, m_conTypes ); m_car.populate( m_activity, m_conTypes );
setConnLabel(); setConnLabel();
@ -349,7 +356,7 @@ public class GameConfigDelegate extends DelegateBase
break; break;
} }
} }
}, null ); }, null, this );
break; break;
} }
} }

View file

@ -1,7 +1,7 @@
/* -*- compile-command: "find-and-ant.sh debug install"; -*- */ /* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/* /*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * Copyright 2009-2015 by Eric House (xwords@eehouse.org). All rights
* rights reserved. * reserved.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
@ -601,9 +601,9 @@ public class GameUtils {
public static void launchEmailInviteActivity( Activity activity, NetLaunchInfo nli ) public static void launchEmailInviteActivity( Activity activity, NetLaunchInfo nli )
{ {
DbgUtils.logf( "launchEmailInviteActivity: nli=%s", nli.makeLaunchJSON() ); // DbgUtils.logf( "launchEmailInviteActivity: nli=%s", nli.makeLaunchJSON() );
Uri gameUri = nli.makeLaunchUri( activity ); Uri gameUri = nli.makeLaunchUri( activity );
DbgUtils.logf( "launchEmailInviteActivity: uri=%s", gameUri ); // DbgUtils.logf( "launchEmailInviteActivity: uri=%s", gameUri );
String msgString = null == gameUri ? null : gameUri.toString(); String msgString = null == gameUri ? null : gameUri.toString();
if ( null != msgString ) { if ( null != msgString ) {
@ -1043,18 +1043,16 @@ public class GameUtils {
public static void postMoveNotification( Context context, long rowid, public static void postMoveNotification( Context context, long rowid,
LastMoveInfo lmi ) LastMoveInfo lmi )
{ {
if ( null == lmi ) {
DbgUtils.logf( "postMoveNotification: posting nothing for lack"
+ " of lmi" );
} else {
Intent intent = GamesListDelegate.makeRowidIntent( context, rowid );
String msg = "";
if ( null != lmi ) { if ( null != lmi ) {
msg = lmi.format( context ); Intent intent = GamesListDelegate.makeRowidIntent( context, rowid );
} String msg = lmi.format( context );
String title = LocUtils.getString( context, R.string.notify_title_fmt, String title =
LocUtils.getString( context, R.string.notify_title_fmt,
getName( context, rowid ) ); getName( context, rowid ) );
Utils.postNotification( context, intent, title, msg, (int)rowid ); Utils.postNotification( context, intent, title, msg, (int)rowid );
} else {
DbgUtils.logf( "postMoveNotification(): posting nothing for lack"
+ " of lmi" );
} }
} }

View file

@ -48,9 +48,9 @@ public class GamesListActivity extends XWListActivity {
// Trying to debug situation where two of this activity are running at // Trying to debug situation where two of this activity are running at
// once. finish()ing when Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT is // once. finish()ing when Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT is
// passed is not the fix, but perhaps there's another // passed is not the fix, but perhaps there's another
int flags = getIntent().getFlags(); // int flags = getIntent().getFlags();
DbgUtils.logf( "GamesListActivity.onCreate(this=%H): flags=0x%x", // DbgUtils.logf( "GamesListActivity.onCreate(this=%H): flags=0x%x",
this, flags ); // this, flags );
} // onCreate } // onCreate
// called when we're brought to the front (probably as a result of // called when we're brought to the front (probably as a result of

View file

@ -895,7 +895,7 @@ public class GamesListDelegate extends ListDelegateBase
boolean isUpgrade = Utils.firstBootThisVersion( m_activity ); boolean isUpgrade = Utils.firstBootThisVersion( m_activity );
if ( isUpgrade && !s_firstShown ) { if ( isUpgrade && !s_firstShown ) {
if ( LocUtils.getCurLocale( m_activity ).equals( "en" ) ) { if ( LocUtils.getCurLangCode( m_activity ).equals( "en" ) ) {
FirstRunDialog.show( m_activity ); FirstRunDialog.show( m_activity );
} }
s_firstShown = true; s_firstShown = true;
@ -1300,7 +1300,7 @@ public class GamesListDelegate extends ListDelegateBase
// check for updates only serves release builds, so don't offer in // check for updates only serves release builds, so don't offer in
// DEBUG case // DEBUG case
boolean enable = showDbg && !BuildConfig.DEBUG && nothingSelected boolean enable = showDbg && nothingSelected
&& UpdateCheckReceiver.haveToCheck( m_activity ); && UpdateCheckReceiver.haveToCheck( m_activity );
Utils.setItemVisible( menu, R.id.games_menu_checkupdates, enable ); Utils.setItemVisible( menu, R.id.games_menu_checkupdates, enable );
@ -1847,8 +1847,9 @@ public class GamesListDelegate extends ListDelegateBase
// used to connect. // used to connect.
private void startRematch( Intent intent ) private void startRematch( Intent intent )
{ {
if ( XWApp.REMATCH_SUPPORTED ) {
long rowid = intent.getLongExtra( REMATCH_ROWID_EXTRA, -1 ); long rowid = intent.getLongExtra( REMATCH_ROWID_EXTRA, -1 );
if ( XWApp.REMATCH_SUPPORTED && -1 != rowid ) { if ( -1 != rowid ) {
String btAddr = intent.getStringExtra( REMATCH_BTADDR_EXTRA ); String btAddr = intent.getStringExtra( REMATCH_BTADDR_EXTRA );
String phone = intent.getStringExtra( REMATCH_PHONE_EXTRA ); String phone = intent.getStringExtra( REMATCH_PHONE_EXTRA );
String relayID = intent.getStringExtra( REMATCH_RELAYID_EXTRA ); String relayID = intent.getStringExtra( REMATCH_RELAYID_EXTRA );
@ -1862,8 +1863,8 @@ public class GamesListDelegate extends ListDelegateBase
long groupID = DBUtils.getGroupForGame( m_activity, rowid ); long groupID = DBUtils.getGroupForGame( m_activity, rowid );
String gameName = "rematch"; // FIX ME :-) String gameName = "rematch"; // FIX ME :-)
newid = GameUtils.makeNewMultiGame( m_activity, groupID, addrs, newid = GameUtils.makeNewMultiGame( m_activity, groupID,
gameName ); addrs, gameName );
DBUtils.addRematchInfo( m_activity, newid, btAddr, phone, DBUtils.addRematchInfo( m_activity, newid, btAddr, phone,
relayID ); relayID );
@ -1871,6 +1872,7 @@ public class GamesListDelegate extends ListDelegateBase
launchGame( newid ); launchGame( newid );
} }
} }
}
private void tryAlert( Intent intent ) private void tryAlert( Intent intent )
{ {
@ -2104,12 +2106,6 @@ public class GamesListDelegate extends ListDelegateBase
launchGame( rowid, true ); launchGame( rowid, true );
} }
// private void makeNewBTGame( NetLaunchInfo nli )
// {
// long rowid = GameUtils.makeNewBTGame( m_activity, nli );
// launchGame( rowid, true );
// }
private void tryStartsFromIntent( Intent intent ) private void tryStartsFromIntent( Intent intent )
{ {
startFirstHasDict( intent ); startFirstHasDict( intent );
@ -2128,17 +2124,6 @@ public class GamesListDelegate extends ListDelegateBase
if ( summary.conTypes.contains( CommsAddrRec.CommsConnType.COMMS_CONN_RELAY ) if ( summary.conTypes.contains( CommsAddrRec.CommsConnType.COMMS_CONN_RELAY )
&& summary.roomName.length() == 0 ) { && summary.roomName.length() == 0 ) {
Assert.fail(); Assert.fail();
// If it's unconfigured and of the type RelayGameActivity
// can handle send it there, otherwise use the full-on
// config.
// Class clazz;
// if ( RelayGameDelegate.isSimpleGame( summary ) ) {
// clazz = RelayGameActivity.class;
// } else {
// clazz = GameConfigActivity.class;
// }
// GameUtils.doConfig( m_activity, rowid, clazz );
} else { } else {
if ( checkWarnNoDict( rowid ) ) { if ( checkWarnNoDict( rowid ) ) {
launchGame( rowid ); launchGame( rowid );
@ -2273,8 +2258,10 @@ public class GamesListDelegate extends ListDelegateBase
String btAddr, String phone, String btAddr, String phone,
String relayID ) String relayID )
{ {
Intent intent = null;
if ( XWApp.REMATCH_SUPPORTED ) {
DbgUtils.logf( "makeRematchIntent(btAddr=%s; phone=%s)", btAddr, phone ); DbgUtils.logf( "makeRematchIntent(btAddr=%s; phone=%s)", btAddr, phone );
Intent intent = makeSelfIntent( context ); intent = makeSelfIntent( context );
intent.putExtra( REMATCH_ROWID_EXTRA, rowid ); intent.putExtra( REMATCH_ROWID_EXTRA, rowid );
intent.putExtra( REMATCH_ADDRS_EXTRA, addrTypes.toInt() ); intent.putExtra( REMATCH_ADDRS_EXTRA, addrTypes.toInt() );
if ( null != btAddr ) { if ( null != btAddr ) {
@ -2286,6 +2273,7 @@ public class GamesListDelegate extends ListDelegateBase
if ( null != relayID ) { if ( null != relayID ) {
intent.putExtra( REMATCH_RELAYID_EXTRA, relayID ); intent.putExtra( REMATCH_RELAYID_EXTRA, relayID );
} }
}
return intent; return intent;
} }

View file

@ -185,6 +185,8 @@ public class NetLaunchInfo {
} }
} }
removeUnsupported( supported );
dict = data.getQueryParameter( WORDLIST_KEY ); dict = data.getQueryParameter( WORDLIST_KEY );
String langStr = data.getQueryParameter( LANG_KEY ); String langStr = data.getQueryParameter( LANG_KEY );
lang = Integer.decode( langStr ); lang = Integer.decode( langStr );
@ -235,7 +237,7 @@ public class NetLaunchInfo {
this( gi ); this( gi );
for ( CommsConnType typ : summary.conTypes.getTypes() ) { for ( CommsConnType typ : summary.conTypes.getTypes() ) {
DbgUtils.logf( "NetLaunchInfo(): got type %s", typ.toString() ); // DbgUtils.logf( "NetLaunchInfo(): got type %s", typ.toString() );
switch( typ ) { switch( typ ) {
case COMMS_CONN_BT: case COMMS_CONN_BT:
addBTInfo(); addBTInfo();
@ -258,12 +260,17 @@ public class NetLaunchInfo {
return m_addrs.contains( typ ); return m_addrs.contains( typ );
} }
public void removeAddress( CommsConnType typ )
{
m_addrs.remove( typ );
}
public String inviteID() public String inviteID()
{ {
String result = m_inviteID; String result = m_inviteID;
if ( null == result ) { if ( null == result ) {
result = GameUtils.formatGameID( m_gameID ); result = GameUtils.formatGameID( m_gameID );
DbgUtils.logf( "inviteID(): m_inviteID null so substituting %s", result ); // DbgUtils.logf( "inviteID(): m_inviteID null so substituting %s", result );
} }
return result; return result;
} }
@ -274,7 +281,7 @@ public class NetLaunchInfo {
if ( 0 == result ) { if ( 0 == result ) {
Assert.assertNotNull( m_inviteID ); Assert.assertNotNull( m_inviteID );
result = Integer.parseInt( m_inviteID, 16 ); result = Integer.parseInt( m_inviteID, 16 );
DbgUtils.logf( "gameID(): m_gameID -1 so substituting %d", result ); // DbgUtils.logf( "gameID(): m_gameID -1 so substituting %d", result );
m_gameID = result; m_gameID = result;
} }
Assert.assertTrue( 0 != result ); Assert.assertTrue( 0 != result );
@ -364,6 +371,7 @@ public class NetLaunchInfo {
private void init( Context context, String data ) private void init( Context context, String data )
{ {
CommsConnTypeSet supported = CommsConnTypeSet.getSupported( context );
try { try {
JSONObject json = new JSONObject( data ); JSONObject json = new JSONObject( data );
@ -381,7 +389,6 @@ public class NetLaunchInfo {
m_gameID = json.optInt( MultiService.GAMEID, 0 ); m_gameID = json.optInt( MultiService.GAMEID, 0 );
// Try each type // Try each type
CommsConnTypeSet supported = CommsConnTypeSet.getSupported( context );
for ( CommsConnType typ : supported.getTypes() ) { for ( CommsConnType typ : supported.getTypes() ) {
if ( hasAddrs && !m_addrs.contains( typ ) ) { if ( hasAddrs && !m_addrs.contains( typ ) ) {
continue; continue;
@ -417,6 +424,8 @@ public class NetLaunchInfo {
DbgUtils.loge( jse ); DbgUtils.loge( jse );
} }
removeUnsupported( supported );
calcValid(); calcValid();
} }
@ -460,10 +469,11 @@ public class NetLaunchInfo {
} }
Uri result = ub.build(); Uri result = ub.build();
// Now test if ( BuildConfig.DEBUG ) { // Test...
DbgUtils.logf( "testing %s...", result.toString() ); DbgUtils.logf( "testing %s...", result.toString() );
NetLaunchInfo instance = new NetLaunchInfo( context, result ); NetLaunchInfo instance = new NetLaunchInfo( context, result );
Assert.assertTrue( instance.isValid() ); Assert.assertTrue( instance.isValid() );
}
return result; return result;
} }
@ -500,7 +510,7 @@ public class NetLaunchInfo {
public boolean isValid() public boolean isValid()
{ {
DbgUtils.logf( "NetLaunchInfo(%s).isValid() => %b", toString(), m_valid ); // DbgUtils.logf( "NetLaunchInfo(%s).isValid() => %b", toString(), m_valid );
return m_valid; return m_valid;
} }
@ -523,10 +533,20 @@ public class NetLaunchInfo {
&& 0 != gameID(); && 0 != gameID();
} }
private void removeUnsupported( CommsConnTypeSet supported )
{
for ( Iterator<CommsConnType> iter = m_addrs.iterator();
iter.hasNext(); ) {
if ( !supported.contains( iter.next() ) ) {
iter.remove();
}
}
}
private void calcValid() private void calcValid()
{ {
boolean valid = hasCommon() && null != m_addrs; boolean valid = hasCommon() && null != m_addrs;
DbgUtils.logf( "calcValid(%s)", toString() ); // DbgUtils.logf( "calcValid(%s)", toString() );
if ( valid ) { if ( valid ) {
for ( Iterator<CommsConnType> iter = m_addrs.iterator(); for ( Iterator<CommsConnType> iter = m_addrs.iterator();
valid && iter.hasNext(); ) { valid && iter.hasNext(); ) {

View file

@ -46,6 +46,7 @@ public class NetStateCache {
private static AtomicBoolean s_haveReceiver = new AtomicBoolean( false ); private static AtomicBoolean s_haveReceiver = new AtomicBoolean( false );
private static HashSet<StateChangedIf> s_ifs; private static HashSet<StateChangedIf> s_ifs;
private static boolean s_netAvail = false; private static boolean s_netAvail = false;
private static boolean s_isWifi;
private static PvtBroadcastReceiver s_receiver; private static PvtBroadcastReceiver s_receiver;
private static final boolean s_onSim = Build.PRODUCT.contains("sdk"); private static final boolean s_onSim = Build.PRODUCT.contains("sdk");
@ -71,6 +72,11 @@ public class NetStateCache {
return s_netAvail || s_onSim; return s_netAvail || s_onSim;
} }
public static boolean onWifi()
{
return s_isWifi;
}
public static void reset( Context context ) public static void reset( Context context )
{ {
synchronized( s_haveReceiver ) { synchronized( s_haveReceiver ) {
@ -95,8 +101,8 @@ public class NetStateCache {
NetworkInfo ni = connMgr.getActiveNetworkInfo(); NetworkInfo ni = connMgr.getActiveNetworkInfo();
s_netAvail = ni != null && ni.isAvailable() && ni.isConnected(); s_netAvail = ni != null && ni.isAvailable() && ni.isConnected();
DbgUtils.logf( "NetStateCache.initIfNot(): set s_netAvail = %b", // DbgUtils.logf( "NetStateCache.initIfNot(): set s_netAvail = %b",
s_netAvail ); // s_netAvail );
s_receiver = new PvtBroadcastReceiver(); s_receiver = new PvtBroadcastReceiver();
IntentFilter filter = new IntentFilter(); IntentFilter filter = new IntentFilter();
@ -126,7 +132,6 @@ public class NetStateCache {
@Override @Override
public void onReceive( final Context context, Intent intent ) public void onReceive( final Context context, Intent intent )
{ {
DbgUtils.logf( "NetStateCache.onReceive()" );
DbgUtils.assertOnUIThread(); DbgUtils.assertOnUIThread();
if ( intent.getAction(). if ( intent.getAction().
@ -140,6 +145,7 @@ public class NetStateCache {
switch ( state ) { switch ( state ) {
case CONNECTED: case CONNECTED:
netAvail = true; netAvail = true;
s_isWifi = ConnectivityManager.TYPE_WIFI == ni.getType();
break; break;
case DISCONNECTED: case DISCONNECTED:
netAvail = false; netAvail = false;
@ -152,8 +158,6 @@ public class NetStateCache {
if ( s_netAvail != netAvail ) { if ( s_netAvail != netAvail ) {
s_netAvail = netAvail; // keep current in case we're asked s_netAvail = netAvail; // keep current in case we're asked
DbgUtils.logf( "NetStateCache.onReceive(): set s_netAvail"
+ " = %b", s_netAvail );
// We want to wait for WAIT_STABLE_MILLIS of inactivity // We want to wait for WAIT_STABLE_MILLIS of inactivity
// before informing listeners. So each time there's a // before informing listeners. So each time there's a

View file

@ -21,14 +21,29 @@
package org.eehouse.android.xw4; package org.eehouse.android.xw4;
import android.content.Context; import android.content.Context;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.Socket; import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import javax.net.SocketFactory; import javax.net.SocketFactory;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;
public class NetUtils { public class NetUtils {
public static final String k_PARAMS = "params";
public static final byte PROTOCOL_VERSION = 0; public static final byte PROTOCOL_VERSION = 0;
// from xwrelay.h // from xwrelay.h
public static byte PRX_PUB_ROOMS = 1; public static byte PRX_PUB_ROOMS = 1;
@ -183,6 +198,48 @@ public class NetUtils {
return msgs; return msgs;
} // queryRelay } // queryRelay
protected static HttpPost makePost( Context context, String proc )
{
String url = String.format( "%s/%s",
XWPrefs.getDefaultUpdateUrl( context ),
proc );
HttpPost result;
try {
result = new HttpPost( url );
} catch ( IllegalArgumentException iae ) {
DbgUtils.loge( iae );
result = null;
}
return result;
}
protected static String runPost( HttpPost post, JSONObject param )
{
String result = null;
try {
String jsonStr = param.toString();
List<NameValuePair> nvp = new ArrayList<NameValuePair>();
nvp.add( new BasicNameValuePair( k_PARAMS, jsonStr ) );
post.setEntity( new UrlEncodedFormEntity(nvp) );
// Execute HTTP Post Request
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response = httpclient.execute(post);
HttpEntity entity = response.getEntity();
if ( null != entity ) {
result = EntityUtils.toString( entity );
if ( 0 == result.length() ) {
result = null;
}
}
} catch( java.io.UnsupportedEncodingException uee ) {
DbgUtils.loge( uee );
} catch( java.io.IOException ioe ) {
DbgUtils.loge( ioe );
}
return result;
}
private static int sumStrings( final String[] strs ) private static int sumStrings( final String[] strs )
{ {
int len = 0; int len = 0;

View file

@ -29,16 +29,11 @@ import android.preference.PreferenceActivity;
import org.eehouse.android.xw4.loc.LocUtils; import org.eehouse.android.xw4.loc.LocUtils;
import org.eehouse.android.xw4.DlgDelegate.Action; import org.eehouse.android.xw4.DlgDelegate.Action;
public class PrefsActivity extends PreferenceActivity implements Delegator { public class PrefsActivity extends PreferenceActivity
implements Delegator, DlgDelegate.HasDlgDelegate {
private PrefsDelegate m_dlgt; private PrefsDelegate m_dlgt;
@Override
protected Dialog onCreateDialog( int id )
{
return m_dlgt.onCreateDialog( id );
}
@Override @Override
protected void onCreate( Bundle savedInstanceState ) protected void onCreate( Bundle savedInstanceState )
{ {
@ -88,11 +83,35 @@ public class PrefsActivity extends PreferenceActivity implements Delegator {
super.onDestroy(); super.onDestroy();
} }
protected void showOKOnlyDialog( int msgID ) @Override
protected Dialog onCreateDialog( int id )
{
return m_dlgt.onCreateDialog( id );
}
@Override
public void onPrepareDialog( int id, Dialog dialog )
{
super.onPrepareDialog( id, dialog );
m_dlgt.prepareDialog( DlgID.values()[id], dialog );
}
public void showOKOnlyDialog( int msgID )
{ {
m_dlgt.showOKOnlyDialog( msgID ); m_dlgt.showOKOnlyDialog( msgID );
} }
public void showOKOnlyDialog( String msg )
{
m_dlgt.showOKOnlyDialog( msg );
}
public void showNotAgainDlgThen( int msgID, int prefsKey,
DlgDelegate.Action action )
{
m_dlgt.showNotAgainDlgThen( msgID, prefsKey, action );
}
protected void showConfirmThen( int msg, int posButton, int negButton, protected void showConfirmThen( int msg, int posButton, int negButton,
Action action ) Action action )
{ {

View file

@ -43,7 +43,6 @@ public class RelayReceiver extends BroadcastReceiver {
public static void setTimer( Context context, long interval_millis ) public static void setTimer( Context context, long interval_millis )
{ {
DbgUtils.logf( "RelayReceiver.restartTimer(%d)", interval_millis );
AlarmManager am = AlarmManager am =
(AlarmManager)context.getSystemService( Context.ALARM_SERVICE ); (AlarmManager)context.getSystemService( Context.ALARM_SERVICE );
@ -56,7 +55,6 @@ public class RelayReceiver extends BroadcastReceiver {
long fire_millis = SystemClock.elapsedRealtime() + interval_millis; long fire_millis = SystemClock.elapsedRealtime() + interval_millis;
am.set( AlarmManager.ELAPSED_REALTIME_WAKEUP, fire_millis, pi ); am.set( AlarmManager.ELAPSED_REALTIME_WAKEUP, fire_millis, pi );
} else { } else {
DbgUtils.logf( "RelayReceiver.restartTimer(): cancelling" );
// will happen if user's set getProxyIntervalSeconds to return 0 // will happen if user's set getProxyIntervalSeconds to return 0
am.cancel( pi ); am.cancel( pi );
} }

View file

@ -523,6 +523,15 @@ public class RelayService extends XWService
} }
resetExitTimer(); resetExitTimer();
ConnStatusHandler.showSuccessOut(); ConnStatusHandler.showSuccessOut();
} catch ( java.net.SocketException se ) {
DbgUtils.loge( se );
DbgUtils.logf( "Restarting threads to force"
+ " new socket" );
m_handler.post( new Runnable() {
public void run() {
stopUDPThreadsIf();
}
} );
} catch ( java.io.IOException ioe ) { } catch ( java.io.IOException ioe ) {
DbgUtils.loge( ioe ); DbgUtils.loge( ioe );
} catch ( NullPointerException npe ) { } catch ( NullPointerException npe ) {
@ -579,7 +588,7 @@ public class RelayService extends XWService
if ( !skipAck ) { if ( !skipAck ) {
sendAckIf( header ); sendAckIf( header );
} }
DbgUtils.logf( "RelayService.gotPacket: cmd=%s", header.m_cmd.toString() ); // DbgUtils.logf( "RelayService.gotPacket: cmd=%s", header.m_cmd.toString() );
switch ( header.m_cmd ) { switch ( header.m_cmd ) {
case XWPDEV_UNAVAIL: case XWPDEV_UNAVAIL:
int unavail = dis.readInt(); int unavail = dis.readInt();
@ -605,8 +614,8 @@ public class RelayService extends XWService
case XWPDEV_REGRSP: case XWPDEV_REGRSP:
str = getVLIString( dis ); str = getVLIString( dis );
short maxIntervalSeconds = dis.readShort(); short maxIntervalSeconds = dis.readShort();
DbgUtils.logf( "got relayid %s, maxInterval %d", str, // DbgUtils.logf( "got relayid %s, maxInterval %d", str,
maxIntervalSeconds ); // maxIntervalSeconds );
setMaxIntervalSeconds( maxIntervalSeconds ); setMaxIntervalSeconds( maxIntervalSeconds );
XWPrefs.setRelayDevID( this, str ); XWPrefs.setRelayDevID( this, str );
s_registered = true; s_registered = true;

View file

@ -43,10 +43,7 @@ public class SMSReceiver extends BroadcastReceiver {
for ( int ii = 0; ii < pdus.length; ++ii ) { for ( int ii = 0; ii < pdus.length; ++ii ) {
SmsMessage sms = SmsMessage.createFromPdu((byte[])pdus[ii]); SmsMessage sms = SmsMessage.createFromPdu((byte[])pdus[ii]);
if ( null == sms ) { if ( null != sms ) {
continue;
}
String phone = sms.getOriginatingAddress(); String phone = sms.getOriginatingAddress();
byte[] body = sms.getUserData(); byte[] body = sms.getUserData();
SMSService.handleFrom( context, body, phone ); SMSService.handleFrom( context, body, phone );
@ -55,3 +52,4 @@ public class SMSReceiver extends BroadcastReceiver {
} }
} }
} }
}

View file

@ -30,20 +30,12 @@ import android.content.pm.PackageManager;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.SystemClock; import android.os.SystemClock;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONObject; import org.json.JSONObject;
@ -73,8 +65,8 @@ public class UpdateCheckReceiver extends BroadcastReceiver {
private static final String k_MD5SUM = "md5sum"; private static final String k_MD5SUM = "md5sum";
private static final String k_INDEX = "index"; private static final String k_INDEX = "index";
private static final String k_URL = "url"; private static final String k_URL = "url";
private static final String k_PARAMS = "params";
private static final String k_DEVID = "did"; private static final String k_DEVID = "did";
private static final String k_DEBUG = "dbg";
private static final String k_XLATEINFO = "xlatinfo"; private static final String k_XLATEINFO = "xlatinfo";
private static final String k_STRINGSHASH = "strings"; private static final String k_STRINGSHASH = "strings";
@ -92,10 +84,6 @@ public class UpdateCheckReceiver extends BroadcastReceiver {
public static void restartTimer( Context context ) public static void restartTimer( Context context )
{ {
if ( BuildConfig.DEBUG ) {
DbgUtils.logf( "UpdateCheckReceiver.restartTimer(): dropping because"
+ " debug builds can't be updated" );
} else {
AlarmManager am = AlarmManager am =
(AlarmManager)context.getSystemService( Context.ALARM_SERVICE ); (AlarmManager)context.getSystemService( Context.ALARM_SERVICE );
@ -113,7 +101,6 @@ public class UpdateCheckReceiver extends BroadcastReceiver {
SystemClock.elapsedRealtime() + interval_millis, SystemClock.elapsedRealtime() + interval_millis,
interval_millis, pi ); interval_millis, pi );
} }
}
// Is app upgradeable OR have we installed any dicts? // Is app upgradeable OR have we installed any dicts?
public static boolean haveToCheck( Context context ) public static boolean haveToCheck( Context context )
@ -154,6 +141,7 @@ public class UpdateCheckReceiver extends BroadcastReceiver {
if ( devOK( context ) ) { if ( devOK( context ) ) {
appParams.put( k_DEVOK, true ); appParams.put( k_DEVOK, true );
} }
appParams.put( k_DEBUG, BuildConfig.DEBUG );
params.put( k_APP, appParams ); params.put( k_APP, appParams );
params.put( k_DEVID, XWPrefs.getDevID( context ) ); params.put( k_DEVID, XWPrefs.getDevID( context ) );
} catch ( org.json.JSONException jse ) { } catch ( org.json.JSONException jse ) {
@ -224,48 +212,6 @@ public class UpdateCheckReceiver extends BroadcastReceiver {
return result; return result;
} }
protected static HttpPost makePost( Context context, String proc )
{
String url = String.format( "%s/%s",
XWPrefs.getDefaultUpdateUrl( context ),
proc );
HttpPost result;
try {
result = new HttpPost( url );
} catch ( IllegalArgumentException iae ) {
DbgUtils.loge( iae );
result = null;
}
return result;
}
protected static String runPost( HttpPost post, JSONObject params )
{
String result = null;
try {
String jsonStr = params.toString();
List<NameValuePair> nvp = new ArrayList<NameValuePair>();
nvp.add( new BasicNameValuePair( k_PARAMS, jsonStr ) );
post.setEntity( new UrlEncodedFormEntity(nvp) );
// Execute HTTP Post Request
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response = httpclient.execute(post);
HttpEntity entity = response.getEntity();
if ( null != entity ) {
result = EntityUtils.toString( entity );
if ( 0 == result.length() ) {
result = null;
}
}
} catch( java.io.UnsupportedEncodingException uee ) {
DbgUtils.loge( uee );
} catch( java.io.IOException ioe ) {
DbgUtils.loge( ioe );
}
return result;
}
private static JSONObject makeDictParams( Context context, private static JSONObject makeDictParams( Context context,
DictUtils.DictAndLoc dal, DictUtils.DictAndLoc dal,
int index ) int index )
@ -314,10 +260,10 @@ public class UpdateCheckReceiver extends BroadcastReceiver {
@Override protected String doInBackground( Void... unused ) @Override protected String doInBackground( Void... unused )
{ {
HttpPost post = makePost( m_context, "getUpdates" ); HttpPost post = NetUtils.makePost( m_context, "getUpdates" );
String json = null; String json = null;
if ( null != post ) { if ( null != post ) {
json = runPost( post, m_params ); json = NetUtils.runPost( post, m_params );
} }
return json; return json;
} }

View file

@ -204,8 +204,8 @@ public class Utils {
Intents is to send a different second param each time, Intents is to send a different second param each time,
though the docs say that param's ignored. though the docs say that param's ignored.
*/ */
PendingIntent pi = PendingIntent pi = null == intent ? null
PendingIntent.getActivity( context, Utils.nextRandomInt(), intent, : PendingIntent.getActivity( context, Utils.nextRandomInt(), intent,
PendingIntent.FLAG_ONE_SHOT ); PendingIntent.FLAG_ONE_SHOT );
Notification notification = Notification notification =

View file

@ -42,7 +42,7 @@ public class XWApp extends Application {
public static final boolean DEBUG_EXP_TIMERS = false; public static final boolean DEBUG_EXP_TIMERS = false;
public static final boolean GCM_IGNORED = false; public static final boolean GCM_IGNORED = false;
public static final boolean UDP_ENABLED = true; public static final boolean UDP_ENABLED = true;
public static final boolean SMS_INVITE_ENABLED = false; public static final boolean SMS_INVITE_ENABLED = true;
public static final boolean LOCUTILS_ENABLED = false; public static final boolean LOCUTILS_ENABLED = false;
public static final String SMS_PUBLIC_HEADER = "-XW4"; public static final String SMS_PUBLIC_HEADER = "-XW4";

View file

@ -55,10 +55,10 @@ public class XWConnAddrPreference extends DialogPreference {
{ {
LocUtils.xlateView( m_context, view ); LocUtils.xlateView( m_context, view );
m_view = (ConnViaViewLayout)view.findViewById( R.id.conn_types ); m_view = (ConnViaViewLayout)view.findViewById( R.id.conn_types );
final PrefsActivity activity = (PrefsActivity)m_context;
m_view.configure( XWPrefs.getAddrTypes( m_context ), m_view.configure( XWPrefs.getAddrTypes( m_context ),
new ConnViaViewLayout.CheckEnabledWarner() { new ConnViaViewLayout.CheckEnabledWarner() {
public void warnDisabled( CommsConnType typ ) { public void warnDisabled( CommsConnType typ ) {
PrefsActivity activity = (PrefsActivity)m_context;
switch( typ ) { switch( typ ) {
case COMMS_CONN_SMS: case COMMS_CONN_SMS:
activity.showConfirmThen( R.string.warn_sms_disabled, activity.showConfirmThen( R.string.warn_sms_disabled,
@ -80,14 +80,13 @@ public class XWConnAddrPreference extends DialogPreference {
PrefsActivity activity = (PrefsActivity)m_context; PrefsActivity activity = (PrefsActivity)m_context;
activity.showOKOnlyDialog( R.string.warn_no_comms ); activity.showOKOnlyDialog( R.string.warn_no_comms );
} }
} ); }, activity );
} }
@Override @Override
public void onClick( DialogInterface dialog, int which ) public void onClick( DialogInterface dialog, int which )
{ {
if ( AlertDialog.BUTTON_POSITIVE == which ) { if ( AlertDialog.BUTTON_POSITIVE == which ) {
DbgUtils.logf( "ok pressed" );
CommsConnTypeSet curSet = m_view.getTypes(); CommsConnTypeSet curSet = m_view.getTypes();
XWPrefs.setAddrTypes( m_context, curSet ); XWPrefs.setAddrTypes( m_context, curSet );
setSummary( curSet.toString( m_context ) ); setSummary( curSet.toString( m_context ) );

View file

@ -270,6 +270,11 @@ public class CommsAddrRec {
} }
} }
public void remove( CommsConnType typ )
{
conTypes.remove( typ );
}
public boolean changesMatter( final CommsAddrRec other ) public boolean changesMatter( final CommsAddrRec other )
{ {
boolean matter = ! conTypes.equals( other.conTypes ); boolean matter = ! conTypes.equals( other.conTypes );

View file

@ -30,6 +30,7 @@ import org.json.JSONObject;
import org.eehouse.android.xw4.DbgUtils; import org.eehouse.android.xw4.DbgUtils;
import org.eehouse.android.xw4.R; import org.eehouse.android.xw4.R;
import org.eehouse.android.xw4.Utils; import org.eehouse.android.xw4.Utils;
import org.eehouse.android.xw4.XWApp;
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType; import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnTypeSet; import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnTypeSet;
import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole; import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole;
@ -246,6 +247,13 @@ public class GameSummary {
{ {
boolean result = conTypes.contains( CommsConnType.COMMS_CONN_RELAY ) boolean result = conTypes.contains( CommsConnType.COMMS_CONN_RELAY )
&& (null == relayID || 0 == relayID.length()); && (null == relayID || 0 == relayID.length());
if ( result ) {
// Don't report it as unconnected if a game's happening
// anyway, e.g. via BT.
result = 0 > turn && !gameOver;
}
// DbgUtils.logf( "relayConnectPending()=>%b (turn=%d)", result,
// turn );
return result; return result;
} }
@ -422,6 +430,7 @@ public class GameSummary {
public boolean hasRematchInfo() public boolean hasRematchInfo()
{ {
boolean found = false; boolean found = false;
if ( XWApp.REMATCH_SUPPORTED ) {
String[] keys = { EXTRA_REMATCH_BTADDR, String[] keys = { EXTRA_REMATCH_BTADDR,
EXTRA_REMATCH_PHONE, EXTRA_REMATCH_PHONE,
EXTRA_REMATCH_RELAY, EXTRA_REMATCH_RELAY,
@ -433,6 +442,7 @@ public class GameSummary {
} }
} }
DbgUtils.logf( "hasRematchInfo() => %b", found ); DbgUtils.logf( "hasRematchInfo() => %b", found );
}
return found; return found;
} }

View file

@ -234,7 +234,6 @@ public class UtilCtxtImpl implements UtilCtxt {
if ( 0 != pluralsId ) { if ( 0 != pluralsId ) {
result = LocUtils.getQuantityString( m_context, pluralsId, quantity ); result = LocUtils.getQuantityString( m_context, pluralsId, quantity );
} }
DbgUtils.logf( "UtilCtxtImpl.getUserQuantityString() => %s", result );
return result; return result;
} }
@ -303,7 +302,6 @@ public class UtilCtxtImpl implements UtilCtxt {
{ {
Assert.assertTrue( XWApp.SMSSUPPORTED ); Assert.assertTrue( XWApp.SMSSUPPORTED );
boolean same = PhoneNumberUtils.compare( m_context, num1, num2 ); boolean same = PhoneNumberUtils.compare( m_context, num1, num2 );
DbgUtils.logf( "phoneNumbersSame => %b", same );
return same; return same;
} }

View file

@ -1048,10 +1048,12 @@ board_commitTurn( BoardCtxt* board )
|| util_userQuery( board->util, QUERY_COMMIT_TURN, || util_userQuery( board->util, QUERY_COMMIT_TURN,
stream ) ) { stream ) ) {
result = server_commitMove( board->server ) || result; result = server_commitMove( board->server ) || result;
/* invalidate any selected tiles in case we'll be drawing /* invalidate all tiles in case we'll be drawing this tray
this tray again rather than some other -- as is the again rather than some other -- as is the case in a
case in a two-player game where one's a robot. */ two-player game where one's a robot. We really only
board_invalTrayTiles( board, pti->traySelBits ); need the selected tiles and the rightmost (in case it's
showing points-this-turn), but this is easier. */
board_invalTrayTiles( board, ALLTILES );
pti->traySelBits = 0x00; pti->traySelBits = 0x00;
} }
} }

View file

@ -1392,23 +1392,20 @@ sendMsg( CommsCtxt* comms, MsgQueueElem* elem )
const CommsAddrRec* addrP; const CommsAddrRec* addrP;
(void)channelToAddress( comms, channelNo, &addrP ); (void)channelToAddress( comms, channelNo, &addrP );
if ( NULL == addrP ) { if ( NULL == addrP || !addr_hasType( addrP, typ ) ) {
XP_LOGF( TAGFMT() "no addr for channel so using comms'", TAGPRMS ); XP_LOGF( TAGFMT() "no addr for channel or addr type %s"
" so using comms'", ConnType2Str(typ), TAGPRMS );
comms_getAddr( comms, &addr ); comms_getAddr( comms, &addr );
} else { } else {
addr = *addrP; addr = *addrP;
} }
XP_ASSERT( addr_hasType( &addr, typ ) );
XP_ASSERT( !!comms->procs.send ); XP_ASSERT( !!comms->procs.send );
if ( addr_hasType( &addr, typ ) ) {
XP_U32 gameid = gameID( comms ); XP_U32 gameid = gameID( comms );
logAddr( comms, &addr, __func__ ); logAddr( comms, &addr, __func__ );
nSent = (*comms->procs.send)( elem->msg, elem->len, &addr, typ, nSent = (*comms->procs.send)( elem->msg, elem->len, &addr, typ,
gameid, comms->procs.closure ); gameid, comms->procs.closure );
} else {
XP_LOGF( TAGFMT() "not sending b/c type %s missing from addr",
TAGPRMS, ConnType2Str(typ) );
}
break; break;
} }
} /* switch */ } /* switch */

View file

@ -1927,6 +1927,7 @@ nextTurn( ServerCtxt* server, XP_S16 nxtTurn )
} else { } else {
XP_LOGF( "%s: Doing nothing; waiting for server to end game", XP_LOGF( "%s: Doing nothing; waiting for server to end game",
__func__ ); __func__ );
setTurn( server, -1 );
/* I'm the client. Do ++nothing++. */ /* I'm the client. Do ++nothing++. */
} }
} }

View file

@ -0,0 +1,35 @@
# -*- mode: makefile; compile-command: "make -f Makefile.CSW12"; -*-
# Copyright 2002 by Eric House (xwords@eehouse.org). All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
XWLANG=CSW15
LANGCODE=en_US
TARGET_TYPE=WINCE
DICTNOTE = "Submitted by a user, claims equivalence with Collins Scrabble Words 2015"
include ../Makefile.langcommon
SOURCEDICT ?= $(XWDICTPATH)/English/CSW15.txt.gz
$(XWLANG)Main.dict.gz: $(SOURCEDICT) Makefile
zcat $< | tr -d '\r' | awk '{print $$1}' | tr [a-z] [A-Z] | \
grep -e "^[A-Z]\{2,15\}$$" | gzip -c > $@
# Everything but creating of the Main.dict file is inherited from the
# "parent" Makefile.langcommon in the parent directory.
clean: clean_common
rm -f $(XWLANG)Main.dict.gz *.bin $(XWLANG)*.pdb $(XWLANG)*.seb

View file

@ -631,6 +631,7 @@ typedef enum {
,CMD_SPLITPACKETS ,CMD_SPLITPACKETS
,CMD_CHAT ,CMD_CHAT
,CMD_USEUDP ,CMD_USEUDP
,CMD_NOUDP
,CMD_DROPSENDRELAY ,CMD_DROPSENDRELAY
,CMD_DROPRCVRELAY ,CMD_DROPRCVRELAY
,CMD_DROPSENDSMS ,CMD_DROPSENDSMS
@ -747,7 +748,8 @@ static CmdInfoRec CmdInfoRecs[] = {
,{ CMD_SPLITPACKETS, true, "split-packets", "send tcp packets in " ,{ CMD_SPLITPACKETS, true, "split-packets", "send tcp packets in "
"sections every random MOD <n> seconds to test relay reassembly" } "sections every random MOD <n> seconds to test relay reassembly" }
,{ CMD_CHAT, true, "send-chat", "send a chat every <n> seconds" } ,{ CMD_CHAT, true, "send-chat", "send a chat every <n> seconds" }
,{ CMD_USEUDP, false, "use-udp", "connect to relay new-style, via udp not tcp" } ,{ CMD_USEUDP, false, "use-udp", "connect to relay new-style, via udp not tcp (on by default)" }
,{ CMD_NOUDP, false, "no-use-udp", "connect to relay old-style, via tcp not udp" }
,{ CMD_DROPSENDRELAY, false, "drop-send-relay", "start new games with relay send disabled" } ,{ CMD_DROPSENDRELAY, false, "drop-send-relay", "start new games with relay send disabled" }
,{ CMD_DROPRCVRELAY, false, "drop-receive-relay", "start new games with relay receive disabled" } ,{ CMD_DROPRCVRELAY, false, "drop-receive-relay", "start new games with relay receive disabled" }
@ -2085,6 +2087,8 @@ main( int argc, char** argv )
mainParams.allowPeek = XP_TRUE; mainParams.allowPeek = XP_TRUE;
mainParams.showRobotScores = XP_FALSE; mainParams.showRobotScores = XP_FALSE;
mainParams.useMmap = XP_TRUE; mainParams.useMmap = XP_TRUE;
mainParams.useUdp = true;
mainParams.dbName = "xwgames.sql";
char* envDictPath = getenv( "XW_DICTDIR" ); char* envDictPath = getenv( "XW_DICTDIR" );
XP_LOGF( "%s: envDictPath=%s", __func__, envDictPath ); XP_LOGF( "%s: envDictPath=%s", __func__, envDictPath );
@ -2189,6 +2193,7 @@ main( int argc, char** argv )
break; break;
case CMD_GAMEFILE: case CMD_GAMEFILE:
mainParams.fileName = optarg; mainParams.fileName = optarg;
mainParams.dbName = NULL; /* clear the default */
break; break;
case CMD_DBFILE: case CMD_DBFILE:
mainParams.dbName = optarg; mainParams.dbName = optarg;
@ -2206,6 +2211,7 @@ main( int argc, char** argv )
"disabling XWFEATURE_SEARCHLIMIT" ); "disabling XWFEATURE_SEARCHLIMIT" );
# endif # endif
mainParams.dbFileName = optarg; mainParams.dbFileName = optarg;
mainParams.dbName = NULL;
break; break;
case CMD_GAMEDB_ID: case CMD_GAMEDB_ID:
mainParams.dbFileID = atoi(optarg); mainParams.dbFileID = atoi(optarg);
@ -2369,6 +2375,9 @@ main( int argc, char** argv )
case CMD_USEUDP: case CMD_USEUDP:
mainParams.useUdp = true; mainParams.useUdp = true;
break; break;
case CMD_NOUDP:
mainParams.useUdp = false;
break;
case CMD_DROPSENDRELAY: case CMD_DROPSENDRELAY:
mainParams.commsDisableds[COMMS_CONN_RELAY][1] = XP_TRUE; mainParams.commsDisableds[COMMS_CONN_RELAY][1] = XP_TRUE;

View file

@ -44,6 +44,7 @@
static DBMgr* s_instance = NULL; static DBMgr* s_instance = NULL;
#define MAX_NUM_PLAYERS 4 #define MAX_NUM_PLAYERS 4
#define MAX_WAIT_SECONDS (5*60) // five minutes
static int here_less_seed( const char* seeds, int perDeviceSum, static int here_less_seed( const char* seeds, int perDeviceSum,
unsigned short seed ); unsigned short seed );
@ -368,8 +369,6 @@ DBMgr::RegisterDevice( const DevID* host, int clientVersion,
{ {
DevIDRelay devID; DevIDRelay devID;
assert( host->m_devIDType != ID_TYPE_NONE ); assert( host->m_devIDType != ID_TYPE_NONE );
int ii;
bool success;
// if it's already present, just return // if it's already present, just return
devID = getDevID( host ); devID = getDevID( host );
@ -383,7 +382,7 @@ DBMgr::RegisterDevice( const DevID* host, int clientVersion,
// coming from random, but test with increasing values initially to make // coming from random, but test with increasing values initially to make
// sure duplicates are detected. // sure duplicates are detected.
const char* devidStr = host->m_devIDString.c_str(); const char* devidStr = host->m_devIDString.c_str();
for ( success = false, ii = 0; !success; ++ii ) { for ( bool success = false, ii = 0; !success; ++ii ) {
assert( 10 > ii ); // better to check that we're looping BECAUSE assert( 10 > ii ); // better to check that we're looping BECAUSE
// of uniqueness problem. // of uniqueness problem.
do { do {
@ -393,9 +392,9 @@ DBMgr::RegisterDevice( const DevID* host, int clientVersion,
QueryBuilder qb; QueryBuilder qb;
qb.appendQueryf( "INSERT INTO " DEVICES_TABLE " (id, devTypes[1]," qb.appendQueryf( "INSERT INTO " DEVICES_TABLE " (id, devTypes[1],"
" devids[1], clntVers, versdesc, model, osvers)" " devids[1], clntVers, versdesc, model, osvers)"
" VALUES($$, $$, $$, $$, $$, $$, $$)" ); " VALUES($$, $$, $$, $$, $$, $$, $$)" )
qb.appendParam( devID ) .appendParam( devID )
.appendParam( host->m_devIDType ) .appendParam( host->m_devIDType )
.appendParam( devidStr ) .appendParam( devidStr )
.appendParam( clientVersion ) .appendParam( clientVersion )
@ -749,6 +748,34 @@ DBMgr::KillGame( const char* const connName, int hid )
execSql( query ); execSql( query );
} }
void
DBMgr::WaitDBConn( void )
{
int nSeconds = 0;
int toSleep = 1;
for ( ; ; ) {
PGconn* conn = DBMgr::getThreadConn();
if ( !!conn ) {
ConnStatusType status = PQstatus( conn );
if ( CONNECTION_OK == status ) {
break;
}
}
toSleep *= 2;
if ( toSleep > MAX_WAIT_SECONDS ) {
toSleep = MAX_WAIT_SECONDS;
}
(void)sleep( toSleep );
nSeconds += toSleep;
logf( XW_LOGERROR, "%s: waiting for postgres; %d seconds so far", __func__,
nSeconds );
}
logf( XW_LOGERROR, "%s() done", __func__ );
}
void void
DBMgr::ClearCIDs( void ) DBMgr::ClearCIDs( void )
{ {
@ -875,6 +902,19 @@ DBMgr::readArray( const char* const connName, const char* column, int arr[] ) /
PQclear( result ); PQclear( result );
} }
// parse something created by comms.c's formatRelayID
DevIDRelay
DBMgr::getDevID( string& relayID )
{
size_t pos = relayID.find_first_of( '/' );
string connName = relayID.substr( 0, pos );
int hid = relayID[pos + 1] - '0';
DevIDRelay result = getDevID( connName.c_str(), hid );
// Not an error. Remove or downlog when confirm working
logf( XW_LOGERROR, "%s(%s) => %d", __func__, relayID.c_str(), result );
return result;
}
DevIDRelay DevIDRelay
DBMgr::getDevID( const char* connName, int hid ) DBMgr::getDevID( const char* connName, int hid )
{ {
@ -1332,7 +1372,12 @@ DBMgr::getThreadConn( void )
params.catf( "port = %d ", port ); params.catf( "port = %d ", port );
conn = PQconnectdb( params.c_str() ); conn = PQconnectdb( params.c_str() );
if ( CONNECTION_OK == PQstatus( conn ) ) {
pthread_setspecific( m_conn_key, conn ); pthread_setspecific( m_conn_key, conn );
} else {
PQfinish( conn );
conn = NULL;
}
} }
return conn; return conn;
} }

View file

@ -63,6 +63,8 @@ class DBMgr {
~DBMgr(); ~DBMgr();
void WaitDBConn( void );
void ClearCIDs( void ); void ClearCIDs( void );
void AddNew( const char* cookie, const char* connName, CookieID cid, void AddNew( const char* cookie, const char* connName, CookieID cid,
@ -146,6 +148,8 @@ class DBMgr {
void RemoveStoredMessage( const int msgID ); void RemoveStoredMessage( const int msgID );
void RemoveStoredMessages( vector<int>& ids ); void RemoveStoredMessages( vector<int>& ids );
DevIDRelay getDevID( string& relayID );
private: private:
DBMgr(); DBMgr();
bool execSql( const string& query ); bool execSql( const string& query );

View file

@ -14,7 +14,8 @@ def usage():
def sendMsg( devid, msg ): def sendMsg( devid, msg ):
values = { values = {
'registration_ids': [ devid ], 'registration_ids': [ devid ],
'data' : { 'title' : 'Msg from Darth2', 'data' : { 'title' : 'Re: CrossWords',
'teaser' : 'Please tap to read in the app',
'msg' : msg, 'msg' : msg,
} }
} }

View file

@ -374,10 +374,15 @@ getHeader( const uint8_t** bufpp, const uint8_t* end,
uint8_t byt; uint8_t byt;
if ( getNetByte( bufpp, end, &byt ) ) { if ( getNetByte( bufpp, end, &byt ) ) {
header->proto = (XWPDevProto)byt; header->proto = (XWPDevProto)byt;
if ( XWPDEV_PROTO_VERSION_1 == header->proto if ( XWPDEV_PROTO_VERSION_1 != header->proto ) {
&& vli2un( bufpp, end, &header->packetID ) logf( XW_LOGERROR, "%s: bad proto %d", __func__, header->proto );
&& getNetByte( bufpp, end, &byt ) } else if ( !vli2un( bufpp, end, &header->packetID ) ) {
&& byt < XWPDEV_N_ELEMS ) { logf( XW_LOGERROR, "%s: can't get packet id", __func__ );
} else if ( !getNetByte( bufpp, end, &byt ) ) {
logf( XW_LOGERROR, "%s: can't get cmd", __func__ );
} else if ( XWPDEV_N_ELEMS <= byt ) {
logf( XW_LOGERROR, "%s: cmd %d too high", __func__, byt );
} else {
header->cmd = (XWRelayReg)byt; header->cmd = (XWRelayReg)byt;
success = true; success = true;
} }
@ -838,6 +843,22 @@ post_upgrade( DevIDRelay devid )
(void)post_or_store( devid, packet, packetID, NULL, NULL ); (void)post_or_store( devid, packet, packetID, NULL, NULL );
} }
void
post_invite( DevIDRelay sender, DevIDRelay invitee, const uint8_t* ptr, size_t len )
{
vector<uint8_t> packet;
uint32_t packetID;
sender = htonl( sender );
assemble_packet( packet, &packetID, XWPDEV_GOTINVITE,
&sender, sizeof(sender),
ptr, len,
NULL );
bool sent = post_or_store( invitee, packet, packetID, NULL, NULL );
logf( XW_LOGINFO, "%s(): post_or_store => %s", __func__,
sent ? "sent" : "stored");
}
/* A CONNECT message from a device gives us the hostID and socket we'll /* A CONNECT message from a device gives us the hostID and socket we'll
* associate with one participant in a relayed session. We'll store this * associate with one participant in a relayed session. We'll store this
* information with the cookie where other participants can find it when they * information with the cookie where other participants can find it when they
@ -1151,6 +1172,7 @@ usage( char* arg0 )
#ifdef DO_HTTP #ifdef DO_HTTP
"\t-w <cport> (localhost port for web interface)\\\n" "\t-w <cport> (localhost port for web interface)\\\n"
#endif #endif
"\t-b (block until postgres connection available)\\\n"
"\t-D (don't become daemon)\\\n" "\t-D (don't become daemon)\\\n"
"\t-F (don't fork and wait to respawn child)\\\n" "\t-F (don't fork and wait to respawn child)\\\n"
"\t-f <conffile> (config file)\\\n" "\t-f <conffile> (config file)\\\n"
@ -1652,6 +1674,7 @@ msgToStr( XWRelayReg msg )
CASE_STR(XWPDEV_UNAVAIL); CASE_STR(XWPDEV_UNAVAIL);
CASE_STR(XWPDEV_REG); CASE_STR(XWPDEV_REG);
CASE_STR(XWPDEV_REGRSP); CASE_STR(XWPDEV_REGRSP);
CASE_STR(XWPDEV_INVITE);
CASE_STR(XWPDEV_KEEPALIVE); CASE_STR(XWPDEV_KEEPALIVE);
CASE_STR(XWPDEV_HAVEMSGS); CASE_STR(XWPDEV_HAVEMSGS);
CASE_STR(XWPDEV_RQSTMSGS); CASE_STR(XWPDEV_RQSTMSGS);
@ -1756,6 +1779,25 @@ handle_udp_packet( UdpThreadClosure* utc )
} }
break; break;
} }
case XWPDEV_INVITE: {
DevIDRelay sender;
string relayID;
if ( getNetLong( &ptr, end, &sender )
&& getNetString( &ptr, end, relayID ) ) {
DevIDRelay invitee;
if ( 0 < relayID.size() ) {
invitee = DBMgr::Get()->getDevID( relayID );
} else if ( !getNetLong( &ptr, end, &invitee ) ) {
break; // failure
}
logf( XW_LOGVERBOSE0, "got invite from %d for %d",
sender, invitee );
post_invite( sender, invitee, ptr, end - ptr );
}
break;
}
case XWPDEV_KEEPALIVE: case XWPDEV_KEEPALIVE:
case XWPDEV_RQSTMSGS: { case XWPDEV_RQSTMSGS: {
DevID devID( ID_TYPE_RELAY ); DevID devID( ID_TYPE_RELAY );
@ -1988,6 +2030,7 @@ main( int argc, char** argv )
const char* maint_str = NULL; const char* maint_str = NULL;
bool doDaemon = true; bool doDaemon = true;
bool doFork = true; bool doFork = true;
bool doBlock = false;
(void)uptime(); /* force capture of start time */ (void)uptime(); /* force capture of start time */
@ -1999,7 +2042,7 @@ main( int argc, char** argv )
first. */ first. */
for ( ; ; ) { for ( ; ; ) {
int opt = getopt(argc, argv, "h?c:p:M:m:n:f:l:t:s:u:w:" int opt = getopt(argc, argv, "bh?c:p:M:m:n:f:l:t:s:u:w:"
"DF" ); "DF" );
if ( opt == -1 ) { if ( opt == -1 ) {
@ -2010,6 +2053,9 @@ main( int argc, char** argv )
case 'h': case 'h':
usage( argv[0] ); usage( argv[0] );
exit( 0 ); exit( 0 );
case 'b':
doBlock = true;
break;
case 'c': case 'c':
ctrlport = atoi( optarg ); ctrlport = atoi( optarg );
break; break;
@ -2160,6 +2206,10 @@ main( int argc, char** argv )
} }
#endif #endif
if ( doBlock ) {
DBMgr::Get()->WaitDBConn();
}
if ( -1 != udpport ) { if ( -1 != udpport ) {
struct sockaddr_in saddr; struct sockaddr_in saddr;
g_udpsock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); g_udpsock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );

View file

@ -108,6 +108,11 @@ enum { XWPDEV_NONE /* 0 is an illegal value */
to check for upgrades; may eventually to check for upgrades; may eventually
replace device needing a timer. */ replace device needing a timer. */
,XWPDEV_INVITE /* dev->relay; format: header, sender relay
id: 4, recipient relay id: 4; nli data:
variable length. */
,XWPDEV_GOTINVITE /* relay->dev */
,XWPDEV_N_ELEMS /* MUST BE LAST */ ,XWPDEV_N_ELEMS /* MUST BE LAST */
} }