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
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,
otherwise in default as before)</li>
@ -60,7 +66,8 @@
it too hard to support this, and non-GSM phones are only
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
wordlists in same language as game</li>
@ -68,13 +75,13 @@
<li>When assigning new tiles, don&apos;t sort tiles to left of
tray divider</li>
<li>Don&apos;t post empty notifications</li>
<li>Remove &quot;Reconnect&quot; button from network status info</li>
<li>Include info for all communication means being used in
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>
</ul>
@ -89,10 +96,11 @@
<li>Look into supporting play via peer-to-peer wifi</li>
</ul>
<p>Please let me know (email eehouse@eehouse.org) what&apos;s broken
and what features you&apos;d most like to see. And if you do get
a crash, please let your device report it to Google so I can see
it!</p>
<p>Please let me know
(email <a href="mailto:xwords@eehouse.org">xwords@eehouse.org</a>)
what&apos;s broken and what features you&apos;d most like to
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>

View file

@ -431,12 +431,9 @@ and_util_getUserString( XW_UtilCtxt* uc, XP_U16 stringCode )
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*
and_util_getUserQuantityString( XW_UtilCtxt* uc, XP_U16 stringCode, XP_U16 quantity )
{
LOG_FUNC();
XP_UCHAR* result = "";
UTIL_CBK_HEADER("getUserQuantityString", "(II)Ljava/lang/String;" );
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];
UTIL_CBK_TAIL();
LOG_RETURNF( "%s", result );
return result;
}

View file

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

View file

@ -14,4 +14,12 @@
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>

View file

@ -128,6 +128,10 @@
<string name="key_invite_multi">key_invite_multi</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 -->
<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
launched to send your invitation. -->
<string name="newgame_invite">Invite now</string>
<string name="newgame_drop_relay">Drop Relay</string>
<!-- section separator (white-on-gray bar) for third section:
bluetooth games -->
@ -1971,6 +1972,10 @@
<!-- -->
<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
%1$s:</string>
@ -2463,9 +2468,45 @@
<string name="checking_for_fmt">Checking for wordlists in %1$s…</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
relay for communication but has been unable to connect, either
because of problems with your device\'s internet connection or
because the relay is not running.\n\nPlease try opening the game again
later.</string>
relay (internet) for communication but has been unable to
connect.\n\nPlease try opening the game again later after
conditions have changed.</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>

View file

@ -1008,6 +1008,7 @@
it immediately because an email or messaging app will be
launched to send your invitation. -->
<string name="newgame_invite">Etivni won</string>
<string name="newgame_drop_relay">Pord Yaler</string>
<!-- section separator (white-on-gray bar) for third section:
bluetooth games -->
<string name="newgame_bt_header">Wen Htooteulb emag</string>
@ -1707,6 +1708,10 @@
<string name="board_menu_dict">Esworb tsildrow</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
%1$s:</string>
@ -2132,9 +2137,35 @@
<string name="checking_title">Gnikcehc</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="seeking_relay">Gnitcennoc ot yaler…</string>
<string name="no_relay_conn">Siht emag si derugifnoc ot esu eht
yaler rof noitacinummoc tub sah neeb elbanu ot ,tcennoc rehtie
esuaceb fo smelborp htiw ruoy ecived\'s tenretni noitcennoc ro
esuaceb eht yaler si ton gninnur.\n\nEsaelp yrt gninepo eht emag niaga
retal.</string>
yaler )tenretni( rof noitacinummoc tub sah neeb elbanu ot
tcennoc.\n\nEsaelp yrt gninepo eht emag niaga retal retfa
snoitidnoc evah degnahc.</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>

View file

@ -1008,6 +1008,7 @@
it immediately because an email or messaging app will be
launched to send your invitation. -->
<string name="newgame_invite">INVITE NOW</string>
<string name="newgame_drop_relay">DROP RELAY</string>
<!-- section separator (white-on-gray bar) for third section:
bluetooth games -->
<string name="newgame_bt_header">NEW BLUETOOTH GAME</string>
@ -1707,6 +1708,10 @@
<string name="board_menu_dict">BROWSE WORDLIST</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
%1$s:</string>
@ -2132,9 +2137,35 @@
<string name="checking_title">CHECKING</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="seeking_relay">CONNECTING TO RELAY…</string>
<string name="no_relay_conn">THIS GAME IS CONFIGURED TO USE THE
RELAY FOR COMMUNICATION BUT HAS BEEN UNABLE TO CONNECT, EITHER
BECAUSE OF PROBLEMS WITH YOUR DEVICE\'S INTERNET CONNECTION OR
BECAUSE THE RELAY IS NOT RUNNING.\n\nPLEASE TRY OPENING THE GAME AGAIN
LATER.</string>
RELAY (INTERNET) FOR COMMUNICATION BUT HAS BEEN UNABLE TO
CONNECT.\n\nPLEASE TRY OPENING THE GAME AGAIN LATER AFTER
CONDITIONS HAVE CHANGED.</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>

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
sélectionnée ? Cette action ne peut pas être annulée.</item>
<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>
<!-- 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. -->
<!--<string name="newgame_invite">Invite now</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:
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">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
%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">É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
communiquer en utilisant le relai mais n\'a pas pu se connecter, soit
à cause de problèmes avec la connexion Internet de votre périphérique,
soit parce que le relai est hors service.\n\n Veuillez réessayer
d\'ouvrir la partie ultérieurement.</string>
communiquer en utilisant le relai (Internet) mais n\'a pas pu se
connecter.\n\nVeuillez réessayer d\'ouvrir la partie ultérieurement,
après que les conditions aient changé.</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>

View file

@ -1099,7 +1099,7 @@ public class BTService extends XWService {
private DataOutputStream connect( BluetoothSocket socket, BTCmd cmd )
{
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
m_adapter.cancelDiscovery();
@ -1112,7 +1112,7 @@ public class BTService extends XWService {
DbgUtils.logf( "connect() to %s successful", name );
} catch ( IOException ioe ) {
dos = null;
DbgUtils.logf( "connect() to %s failed", name );
DbgUtils.logf( "BTService.connect() to %s failed", name );
// logIOE( ioe );
}
return dos;

View file

@ -291,10 +291,7 @@ public class BoardDelegate extends DelegateBase
lstnr = new OnClickListener() {
public void onClick( DialogInterface dlg,
int whichButton ) {
waitCloseGame( false );
GameUtils.deleteGame( m_activity, m_rowid, false );
finish();
deleteAndClose();
}
};
ab.setNegativeButton( R.string.button_delete, lstnr );
@ -432,13 +429,16 @@ public class BoardDelegate extends DelegateBase
.setNegativeButton( R.string.button_no, null )
.create();
break;
case DLG_NOINVITE:
Assert.assertFalse( m_relayConnected );
case DLG_INVITE:
lstnr = new OnClickListener() {
public void onClick( DialogInterface dialog,
int item ) {
if ( m_relayConnected ||
! m_connTypes.contains(CommsConnType.COMMS_CONN_RELAY) ) {
showInviteChoicesThen( Action.LAUNCH_INVITE_ACTION );
} else {
askDropRelay();
}
}
};
OnClickListener lstnr2 = new OnClickListener() {
@ -449,7 +449,7 @@ public class BoardDelegate extends DelegateBase
};
dialog = ab.setTitle( "foo" )
.setMessage( "" )
.setPositiveButton( R.string.newgame_invite, lstnr )
.setPositiveButton( "", lstnr )
.setNegativeButton( R.string.button_close_game, lstnr2 )
.setOnCancelListener( new OnCancelListener() {
public void onCancel( DialogInterface dialog ) {
@ -476,20 +476,39 @@ public class BoardDelegate extends DelegateBase
{
switch( dlgID ) {
case DLG_INVITE:
case DLG_NOINVITE:
AlertDialog ad = (AlertDialog)dialog;
String message;
int titleID = R.string.info_title;;
int titleID;
boolean nukeButton = false;
int buttonTxt = R.string.newgame_invite;
if ( m_summary.hasRematchInfo() ) {
titleID = R.string.info_title;;
message = getString( R.string.rematch_msg );
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 );
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 {
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;
if ( m_nMissing > 1 ) {
@ -506,11 +525,16 @@ public class BoardDelegate extends DelegateBase
message += "\n\n" + getString( R.string.invite_stays );
}
if ( nukeButton ) {
ad.getButton( AlertDialog.BUTTON_POSITIVE ).setVisibility( View.GONE );
}
ad.setMessage( message );
ad.setTitle( titleID );
Button posButton = ad.getButton( AlertDialog.BUTTON_POSITIVE );
posButton.setVisibility( nukeButton ? View.GONE : View.VISIBLE );
if ( !nukeButton ) {
posButton.setText( buttonTxt );
}
break;
default:
super.prepareDialog( dlgID, dialog );
@ -636,11 +660,8 @@ public class BoardDelegate extends DelegateBase
// onResume -- meaning m_gi etc are still null.
m_missingDevs = data.getStringArrayExtra( InviteDelegate.DEVS );
m_missingCounts = data.getIntArrayExtra( InviteDelegate.COUNTS );
if ( BT_INVITE_RESULT == requestCode ) {
m_missingMeans = InviteMeans.BLUETOOTH;
} else {
m_missingMeans = InviteMeans.SMS;
}
m_missingMeans = (BT_INVITE_RESULT == requestCode)
? InviteMeans.BLUETOOTH : InviteMeans.SMS;
break;
}
}
@ -659,9 +680,7 @@ public class BoardDelegate extends DelegateBase
setBackgroundColor();
setKeepScreenOn();
} else if ( ! isFinishing() ) {
if ( !m_relayConnected ) {
showDialog( DlgID.DLG_NOINVITE );
} else if ( 0 < m_nMissing ) {
if ( !m_relayConnected || 0 < m_nMissing ) {
showDialog( DlgID.DLG_INVITE );
}
}
@ -988,6 +1007,12 @@ public class BoardDelegate extends DelegateBase
case NFC_TO_SELF:
GamesListDelegate.sendNFCToSelf( m_activity, makeNFCMessage() );
break;
case DROP_RELAY_ACTION:
dropRelayAndRestart();
break;
case DELETE_AND_EXIT:
deleteAndClose();
break;
default:
handled = false;
}
@ -1027,6 +1052,9 @@ public class BoardDelegate extends DelegateBase
case EMAIL:
NetLaunchInfo nli = new NetLaunchInfo( m_summary, m_gi, 1,
1 + m_nGuestDevs );
if ( !m_relayConnected ) {
nli.removeAddress( CommsConnType.COMMS_CONN_RELAY );
}
GameUtils.launchEmailInviteActivity( m_activity, nli );
break;
default:
@ -1262,15 +1290,17 @@ public class BoardDelegate extends DelegateBase
public void onStatusClicked()
{
final String msg = ConnStatusHandler.getStatusText( m_activity, m_connTypes );
if ( null != msg ) {
post( new Runnable() {
public void run() {
if ( null == msg ) {
askNoAddrsDelete();
} else {
m_dlgBytes = msg;
m_dlgTitle = R.string.info_title;
showDialog( DlgID.DLG_CONNSTAT );
}
} );
}
} );
}
public Handler getHandler()
@ -1278,6 +1308,43 @@ public class BoardDelegate extends DelegateBase
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 )
{
m_jniThread.setSaveDict( getDict );
@ -1367,9 +1434,7 @@ public class BoardDelegate extends DelegateBase
private void handleConndMessage( String room, int devOrder, // <- hostID
boolean allHere, int nMissing )
{
DbgUtils.logf( "BoardDelegate.handleConndMessage(): nMissing = %d", nMissing );
dismissInviteAlerts( nMissing, true );
dismissInviteAlert( nMissing, true );
int naMsg = 0;
int naKey = 0;
@ -1714,21 +1779,21 @@ public class BoardDelegate extends DelegateBase
{
m_connTypes = connTypes;
Assert.assertTrue( isServer || 0 == nMissing );
DbgUtils.logf( "BoardDelegate.informMissing(isServer=%b, nDevs=%d, nMissing=%d)",
isServer, nDevs, nMissing );
// DbgUtils.logf( "BoardDelegate.informMissing(isServer=%b, nDevs=%d, nMissing=%d)",
// isServer, nDevs, nMissing );
m_nGuestDevs = nDevs;
// 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
final DlgID dlgID =
m_relayConnected ? DlgID.DLG_INVITE : DlgID.DLG_NOINVITE;
if ( 0 < nMissing && isServer && !m_haveInvited ) {
if ( null != connTypes && 0 == connTypes.size() ) {
askNoAddrsDelete();
} else if ( 0 < nMissing && isServer && !m_haveInvited ) {
post( new Runnable() {
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.setName( gameName );
XwJNI.gi_from_stream( m_gi, stream );
DbgUtils.logf( "BoardDelegate:after loadGame: gi.nPlayers: %d", m_gi.nPlayers );
String langName = m_gi.langName();
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() {
public void run() {
if ( !m_relayConnected && connected ) {
m_relayConnected = true;
dismissDialog( DlgID.DLG_NOINVITE );
}
if ( 0 == nMissing ) {
if ( 0 == nMissing || m_relayConnected ) {
dismissDialog( DlgID.DLG_INVITE );
}
}
@ -2278,6 +2341,10 @@ public class BoardDelegate extends DelegateBase
int forceChannel = ii + m_nGuestDevs + 1;
NetLaunchInfo nli = new NetLaunchInfo( m_summary, m_gi,
nPlayers, forceChannel );
if ( !m_relayConnected ) {
nli.removeAddress( CommsConnType.COMMS_CONN_RELAY );
}
switch ( m_missingMeans ) {
case BLUETOOTH:
if ( ! m_progressShown ) {
@ -2424,6 +2491,7 @@ public class BoardDelegate extends DelegateBase
private void doRematch()
{
if ( XWApp.REMATCH_SUPPORTED ) {
String phone = null;
String btAddr = null;
String relayID = null;
@ -2453,10 +2521,11 @@ public class BoardDelegate extends DelegateBase
finish();
}
}
}
private void tryRematchInvites()
{
if ( !m_rematchInvitesSent ) {
if ( XWApp.REMATCH_SUPPORTED && !m_rematchInvitesSent ) {
m_rematchInvitesSent = true;
Assert.assertNotNull( m_summary );

View file

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

View file

@ -310,15 +310,7 @@ public class ConnStatusHandler {
// Do the background coloring. Top quarter first
rect.bottom = rect.top + quarterHeight;
record = newestSuccess( connTypes, 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 );
}
drawQuarter( canvas, res, rect, connTypes, enabled, false );
// paint the middle two quarters black to give the icon a
// clear background
@ -330,15 +322,7 @@ public class ConnStatusHandler {
// bottom quarter
rect.top = rect.bottom;
rect.bottom = rect.top + quarterHeight;
record = newestSuccess( connTypes, 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 );
}
drawQuarter( canvas, res, rect, connTypes, enabled, true );
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
// effects the whole method.
// @SuppressWarnings("unchecked")
@ -466,11 +470,13 @@ public class ConnStatusHandler {
while ( iter.hasNext() ) {
CommsConnType connType = iter.next();
SuccessRecord record = recordFor( connType, isIn );
if ( record.successNewer ) {
if ( null == result || result.lastSuccess < record.lastSuccess ) {
result = record;
}
}
}
}
return result;
}
@ -489,7 +495,7 @@ public class ConnStatusHandler {
private static void doSave( Context context )
{
synchronized( s_lockObj ) {
DbgUtils.logf( "ConnStatusHandler:doSave() doing save" );
// DbgUtils.logf( "ConnStatusHandler:doSave() doing save" );
ByteArrayOutputStream bas
= new ByteArrayOutputStream();
try {
@ -529,7 +535,9 @@ public class ConnStatusHandler {
break;
case COMMS_CONN_BT:
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;
case COMMS_CONN_RELAY:
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.loc.LocUtils;
import junit.framework.Assert;
public class ConnViaViewLayout extends LinearLayout {
private CommsConnTypeSet m_curSet;
private DlgDelegate.HasDlgDelegate m_dlgDlgt;
public interface CheckEnabledWarner {
public void warnDisabled( CommsConnType typ );
@ -52,7 +55,8 @@ public class ConnViaViewLayout extends LinearLayout {
protected void configure( CommsConnTypeSet types,
CheckEnabledWarner cew,
SetEmptyWarner sew )
SetEmptyWarner sew,
DlgDelegate.HasDlgDelegate dlgDlgt )
{
m_curSet = (CommsConnTypeSet)types.clone();
@ -60,6 +64,7 @@ public class ConnViaViewLayout extends LinearLayout {
m_disabledWarner = cew;
m_emptyWarner = sew;
m_dlgDlgt = dlgDlgt;
}
protected CommsConnTypeSet getTypes()
@ -88,6 +93,7 @@ public class ConnViaViewLayout extends LinearLayout {
public void onCheckedChanged( CompoundButton buttonView,
boolean isChecked ) {
if ( isChecked ) {
showNotAgainTypeTip( typf );
enabledElseWarn( typf );
m_curSet.add( typf );
} else {
@ -117,4 +123,32 @@ public class ConnViaViewLayout extends LinearLayout {
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 REMOTEDEVS = "REMOTEDEVS";
public static final String EXTRAS = "EXTRAS";
public static final String JSON_EXTRAS = "JSON_EXTRAS";
public static final String DICTLANG = "DICTLANG";
public static final String DICTLIST = "DICTLIST";
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,
String phone, String relayID )
{
if ( XWApp.REMATCH_SUPPORTED ) {
GameLock lock = new GameLock( rowid, true ).lock();
GameSummary summary = getSummary( context, lock );
if ( null != btAddr ) {
@ -387,6 +388,7 @@ public class DBUtils {
saveSummary( context, lock, summary );
lock.unlock();
}
}
public static int countGamesUsingLang( Context context, int lang )
{
@ -570,9 +572,10 @@ public class DBUtils {
long rowid = cursor.getLong( indx1 );
CommsConnTypeSet typs = new CommsConnTypeSet( cursor.getInt(indx2) );
// Better have an address if has pending sends
Assert.assertTrue( 0 < typs.size() );
if ( 0 < typs.size() ) {
result.put( rowid, typs );
}
}
cursor.close();
db.close();
}
@ -718,7 +721,7 @@ public class DBUtils {
cursor.close();
db.close();
}
DbgUtils.logf( "getMostRecentCreate(%d) => %H", gameID, result );
return result;
}
@ -763,7 +766,6 @@ public class DBUtils {
long[][] rowIDss = new long[1][];
String[] relayIDs = getRelayIDs( context, rowIDss );
boolean result = null != relayIDs && 0 < relayIDs.length;
DbgUtils.logf( "haveRelayGames() => %b", result );
return result;
}

View file

@ -525,7 +525,10 @@ public class DelegateBase implements DlgClickNotify,
fmtId = R.string.app_not_found_fmt;
break;
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 ) {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -101,8 +101,15 @@ public class GCMIntentService extends GCMBaseIntentService {
if ( null != value ) {
String title = intent.getStringExtra( "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();
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 {
private GameConfigDelegate m_dlgt;
@Override
public void onCreate( Bundle savedInstanceState )
{
m_dlgt = new GameConfigDelegate( this, savedInstanceState );
super.onCreate( savedInstanceState, m_dlgt );
super.onCreate( savedInstanceState,
new GameConfigDelegate( this, savedInstanceState ) );
} // onCreate
}

View file

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

View file

@ -1,7 +1,7 @@
/* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.
* Copyright 2009-2015 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
@ -601,9 +601,9 @@ public class GameUtils {
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 );
DbgUtils.logf( "launchEmailInviteActivity: uri=%s", gameUri );
// DbgUtils.logf( "launchEmailInviteActivity: uri=%s", gameUri );
String msgString = null == gameUri ? null : gameUri.toString();
if ( null != msgString ) {
@ -1043,18 +1043,16 @@ public class GameUtils {
public static void postMoveNotification( Context context, long rowid,
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 ) {
msg = lmi.format( context );
}
String title = LocUtils.getString( context, R.string.notify_title_fmt,
Intent intent = GamesListDelegate.makeRowidIntent( context, rowid );
String msg = lmi.format( context );
String title =
LocUtils.getString( context, R.string.notify_title_fmt,
getName( context, 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
// once. finish()ing when Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT is
// passed is not the fix, but perhaps there's another
int flags = getIntent().getFlags();
DbgUtils.logf( "GamesListActivity.onCreate(this=%H): flags=0x%x",
this, flags );
// int flags = getIntent().getFlags();
// DbgUtils.logf( "GamesListActivity.onCreate(this=%H): flags=0x%x",
// this, flags );
} // onCreate
// 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 );
if ( isUpgrade && !s_firstShown ) {
if ( LocUtils.getCurLocale( m_activity ).equals( "en" ) ) {
if ( LocUtils.getCurLangCode( m_activity ).equals( "en" ) ) {
FirstRunDialog.show( m_activity );
}
s_firstShown = true;
@ -1300,7 +1300,7 @@ public class GamesListDelegate extends ListDelegateBase
// check for updates only serves release builds, so don't offer in
// DEBUG case
boolean enable = showDbg && !BuildConfig.DEBUG && nothingSelected
boolean enable = showDbg && nothingSelected
&& UpdateCheckReceiver.haveToCheck( m_activity );
Utils.setItemVisible( menu, R.id.games_menu_checkupdates, enable );
@ -1847,8 +1847,9 @@ public class GamesListDelegate extends ListDelegateBase
// used to connect.
private void startRematch( Intent intent )
{
if ( XWApp.REMATCH_SUPPORTED ) {
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 phone = intent.getStringExtra( REMATCH_PHONE_EXTRA );
String relayID = intent.getStringExtra( REMATCH_RELAYID_EXTRA );
@ -1862,8 +1863,8 @@ public class GamesListDelegate extends ListDelegateBase
long groupID = DBUtils.getGroupForGame( m_activity, rowid );
String gameName = "rematch"; // FIX ME :-)
newid = GameUtils.makeNewMultiGame( m_activity, groupID, addrs,
gameName );
newid = GameUtils.makeNewMultiGame( m_activity, groupID,
addrs, gameName );
DBUtils.addRematchInfo( m_activity, newid, btAddr, phone,
relayID );
@ -1871,6 +1872,7 @@ public class GamesListDelegate extends ListDelegateBase
launchGame( newid );
}
}
}
private void tryAlert( Intent intent )
{
@ -2104,12 +2106,6 @@ public class GamesListDelegate extends ListDelegateBase
launchGame( rowid, true );
}
// private void makeNewBTGame( NetLaunchInfo nli )
// {
// long rowid = GameUtils.makeNewBTGame( m_activity, nli );
// launchGame( rowid, true );
// }
private void tryStartsFromIntent( Intent intent )
{
startFirstHasDict( intent );
@ -2128,17 +2124,6 @@ public class GamesListDelegate extends ListDelegateBase
if ( summary.conTypes.contains( CommsAddrRec.CommsConnType.COMMS_CONN_RELAY )
&& summary.roomName.length() == 0 ) {
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 {
if ( checkWarnNoDict( rowid ) ) {
launchGame( rowid );
@ -2273,8 +2258,10 @@ public class GamesListDelegate extends ListDelegateBase
String btAddr, String phone,
String relayID )
{
Intent intent = null;
if ( XWApp.REMATCH_SUPPORTED ) {
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_ADDRS_EXTRA, addrTypes.toInt() );
if ( null != btAddr ) {
@ -2286,6 +2273,7 @@ public class GamesListDelegate extends ListDelegateBase
if ( null != relayID ) {
intent.putExtra( REMATCH_RELAYID_EXTRA, relayID );
}
}
return intent;
}

View file

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

View file

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

View file

@ -21,14 +21,29 @@
package org.eehouse.android.xw4;
import android.content.Context;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
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 static final String k_PARAMS = "params";
public static final byte PROTOCOL_VERSION = 0;
// from xwrelay.h
public static byte PRX_PUB_ROOMS = 1;
@ -183,6 +198,48 @@ public class NetUtils {
return msgs;
} // 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 )
{
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.DlgDelegate.Action;
public class PrefsActivity extends PreferenceActivity implements Delegator {
public class PrefsActivity extends PreferenceActivity
implements Delegator, DlgDelegate.HasDlgDelegate {
private PrefsDelegate m_dlgt;
@Override
protected Dialog onCreateDialog( int id )
{
return m_dlgt.onCreateDialog( id );
}
@Override
protected void onCreate( Bundle savedInstanceState )
{
@ -88,11 +83,35 @@ public class PrefsActivity extends PreferenceActivity implements Delegator {
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 );
}
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,
Action action )
{

View file

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

View file

@ -523,6 +523,15 @@ public class RelayService extends XWService
}
resetExitTimer();
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 ) {
DbgUtils.loge( ioe );
} catch ( NullPointerException npe ) {
@ -579,7 +588,7 @@ public class RelayService extends XWService
if ( !skipAck ) {
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 ) {
case XWPDEV_UNAVAIL:
int unavail = dis.readInt();
@ -605,8 +614,8 @@ public class RelayService extends XWService
case XWPDEV_REGRSP:
str = getVLIString( dis );
short maxIntervalSeconds = dis.readShort();
DbgUtils.logf( "got relayid %s, maxInterval %d", str,
maxIntervalSeconds );
// DbgUtils.logf( "got relayid %s, maxInterval %d", str,
// maxIntervalSeconds );
setMaxIntervalSeconds( maxIntervalSeconds );
XWPrefs.setRelayDevID( this, str );
s_registered = true;

View file

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

View file

@ -30,20 +30,12 @@ import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.SystemClock;
import java.io.File;
import java.util.ArrayList;
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.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
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_INDEX = "index";
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_DEBUG = "dbg";
private static final String k_XLATEINFO = "xlatinfo";
private static final String k_STRINGSHASH = "strings";
@ -92,10 +84,6 @@ public class UpdateCheckReceiver extends BroadcastReceiver {
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)context.getSystemService( Context.ALARM_SERVICE );
@ -113,7 +101,6 @@ public class UpdateCheckReceiver extends BroadcastReceiver {
SystemClock.elapsedRealtime() + interval_millis,
interval_millis, pi );
}
}
// Is app upgradeable OR have we installed any dicts?
public static boolean haveToCheck( Context context )
@ -154,6 +141,7 @@ public class UpdateCheckReceiver extends BroadcastReceiver {
if ( devOK( context ) ) {
appParams.put( k_DEVOK, true );
}
appParams.put( k_DEBUG, BuildConfig.DEBUG );
params.put( k_APP, appParams );
params.put( k_DEVID, XWPrefs.getDevID( context ) );
} catch ( org.json.JSONException jse ) {
@ -224,48 +212,6 @@ public class UpdateCheckReceiver extends BroadcastReceiver {
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,
DictUtils.DictAndLoc dal,
int index )
@ -314,10 +260,10 @@ public class UpdateCheckReceiver extends BroadcastReceiver {
@Override protected String doInBackground( Void... unused )
{
HttpPost post = makePost( m_context, "getUpdates" );
HttpPost post = NetUtils.makePost( m_context, "getUpdates" );
String json = null;
if ( null != post ) {
json = runPost( post, m_params );
json = NetUtils.runPost( post, m_params );
}
return json;
}

View file

@ -204,8 +204,8 @@ public class Utils {
Intents is to send a different second param each time,
though the docs say that param's ignored.
*/
PendingIntent pi =
PendingIntent.getActivity( context, Utils.nextRandomInt(), intent,
PendingIntent pi = null == intent ? null
: PendingIntent.getActivity( context, Utils.nextRandomInt(), intent,
PendingIntent.FLAG_ONE_SHOT );
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 GCM_IGNORED = false;
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 String SMS_PUBLIC_HEADER = "-XW4";

View file

@ -55,10 +55,10 @@ public class XWConnAddrPreference extends DialogPreference {
{
LocUtils.xlateView( m_context, view );
m_view = (ConnViaViewLayout)view.findViewById( R.id.conn_types );
final PrefsActivity activity = (PrefsActivity)m_context;
m_view.configure( XWPrefs.getAddrTypes( m_context ),
new ConnViaViewLayout.CheckEnabledWarner() {
public void warnDisabled( CommsConnType typ ) {
PrefsActivity activity = (PrefsActivity)m_context;
switch( typ ) {
case COMMS_CONN_SMS:
activity.showConfirmThen( R.string.warn_sms_disabled,
@ -80,14 +80,13 @@ public class XWConnAddrPreference extends DialogPreference {
PrefsActivity activity = (PrefsActivity)m_context;
activity.showOKOnlyDialog( R.string.warn_no_comms );
}
} );
}, activity );
}
@Override
public void onClick( DialogInterface dialog, int which )
{
if ( AlertDialog.BUTTON_POSITIVE == which ) {
DbgUtils.logf( "ok pressed" );
CommsConnTypeSet curSet = m_view.getTypes();
XWPrefs.setAddrTypes( m_context, curSet );
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 )
{
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.R;
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.CommsConnTypeSet;
import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole;
@ -246,6 +247,13 @@ public class GameSummary {
{
boolean result = conTypes.contains( CommsConnType.COMMS_CONN_RELAY )
&& (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;
}
@ -422,6 +430,7 @@ public class GameSummary {
public boolean hasRematchInfo()
{
boolean found = false;
if ( XWApp.REMATCH_SUPPORTED ) {
String[] keys = { EXTRA_REMATCH_BTADDR,
EXTRA_REMATCH_PHONE,
EXTRA_REMATCH_RELAY,
@ -433,6 +442,7 @@ public class GameSummary {
}
}
DbgUtils.logf( "hasRematchInfo() => %b", found );
}
return found;
}

View file

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

View file

@ -1048,10 +1048,12 @@ board_commitTurn( BoardCtxt* board )
|| util_userQuery( board->util, QUERY_COMMIT_TURN,
stream ) ) {
result = server_commitMove( board->server ) || result;
/* invalidate any selected tiles in case we'll be drawing
this tray again rather than some other -- as is the
case in a two-player game where one's a robot. */
board_invalTrayTiles( board, pti->traySelBits );
/* invalidate all tiles in case we'll be drawing this tray
again rather than some other -- as is the case in a
two-player game where one's a robot. We really only
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;
}
}

View file

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

View file

@ -1927,6 +1927,7 @@ nextTurn( ServerCtxt* server, XP_S16 nxtTurn )
} else {
XP_LOGF( "%s: Doing nothing; waiting for server to end game",
__func__ );
setTurn( server, -1 );
/* 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_CHAT
,CMD_USEUDP
,CMD_NOUDP
,CMD_DROPSENDRELAY
,CMD_DROPRCVRELAY
,CMD_DROPSENDSMS
@ -747,7 +748,8 @@ static CmdInfoRec CmdInfoRecs[] = {
,{ CMD_SPLITPACKETS, true, "split-packets", "send tcp packets in "
"sections every random MOD <n> seconds to test relay reassembly" }
,{ 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_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.showRobotScores = XP_FALSE;
mainParams.useMmap = XP_TRUE;
mainParams.useUdp = true;
mainParams.dbName = "xwgames.sql";
char* envDictPath = getenv( "XW_DICTDIR" );
XP_LOGF( "%s: envDictPath=%s", __func__, envDictPath );
@ -2189,6 +2193,7 @@ main( int argc, char** argv )
break;
case CMD_GAMEFILE:
mainParams.fileName = optarg;
mainParams.dbName = NULL; /* clear the default */
break;
case CMD_DBFILE:
mainParams.dbName = optarg;
@ -2206,6 +2211,7 @@ main( int argc, char** argv )
"disabling XWFEATURE_SEARCHLIMIT" );
# endif
mainParams.dbFileName = optarg;
mainParams.dbName = NULL;
break;
case CMD_GAMEDB_ID:
mainParams.dbFileID = atoi(optarg);
@ -2369,6 +2375,9 @@ main( int argc, char** argv )
case CMD_USEUDP:
mainParams.useUdp = true;
break;
case CMD_NOUDP:
mainParams.useUdp = false;
break;
case CMD_DROPSENDRELAY:
mainParams.commsDisableds[COMMS_CONN_RELAY][1] = XP_TRUE;

View file

@ -44,6 +44,7 @@
static DBMgr* s_instance = NULL;
#define MAX_NUM_PLAYERS 4
#define MAX_WAIT_SECONDS (5*60) // five minutes
static int here_less_seed( const char* seeds, int perDeviceSum,
unsigned short seed );
@ -368,8 +369,6 @@ DBMgr::RegisterDevice( const DevID* host, int clientVersion,
{
DevIDRelay devID;
assert( host->m_devIDType != ID_TYPE_NONE );
int ii;
bool success;
// if it's already present, just return
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
// sure duplicates are detected.
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
// of uniqueness problem.
do {
@ -393,9 +392,9 @@ DBMgr::RegisterDevice( const DevID* host, int clientVersion,
QueryBuilder qb;
qb.appendQueryf( "INSERT INTO " DEVICES_TABLE " (id, devTypes[1],"
" devids[1], clntVers, versdesc, model, osvers)"
" VALUES($$, $$, $$, $$, $$, $$, $$)" );
" VALUES($$, $$, $$, $$, $$, $$, $$)" )
qb.appendParam( devID )
.appendParam( devID )
.appendParam( host->m_devIDType )
.appendParam( devidStr )
.appendParam( clientVersion )
@ -749,6 +748,34 @@ DBMgr::KillGame( const char* const connName, int hid )
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
DBMgr::ClearCIDs( void )
{
@ -875,6 +902,19 @@ DBMgr::readArray( const char* const connName, const char* column, int arr[] ) /
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
DBMgr::getDevID( const char* connName, int hid )
{
@ -1332,7 +1372,12 @@ DBMgr::getThreadConn( void )
params.catf( "port = %d ", port );
conn = PQconnectdb( params.c_str() );
if ( CONNECTION_OK == PQstatus( conn ) ) {
pthread_setspecific( m_conn_key, conn );
} else {
PQfinish( conn );
conn = NULL;
}
}
return conn;
}

View file

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

View file

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

View file

@ -374,10 +374,15 @@ getHeader( const uint8_t** bufpp, const uint8_t* end,
uint8_t byt;
if ( getNetByte( bufpp, end, &byt ) ) {
header->proto = (XWPDevProto)byt;
if ( XWPDEV_PROTO_VERSION_1 == header->proto
&& vli2un( bufpp, end, &header->packetID )
&& getNetByte( bufpp, end, &byt )
&& byt < XWPDEV_N_ELEMS ) {
if ( XWPDEV_PROTO_VERSION_1 != header->proto ) {
logf( XW_LOGERROR, "%s: bad proto %d", __func__, header->proto );
} else if ( !vli2un( bufpp, end, &header->packetID ) ) {
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;
success = true;
}
@ -838,6 +843,22 @@ post_upgrade( DevIDRelay devid )
(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
* associate with one participant in a relayed session. We'll store this
* information with the cookie where other participants can find it when they
@ -1151,6 +1172,7 @@ usage( char* arg0 )
#ifdef DO_HTTP
"\t-w <cport> (localhost port for web interface)\\\n"
#endif
"\t-b (block until postgres connection available)\\\n"
"\t-D (don't become daemon)\\\n"
"\t-F (don't fork and wait to respawn child)\\\n"
"\t-f <conffile> (config file)\\\n"
@ -1652,6 +1674,7 @@ msgToStr( XWRelayReg msg )
CASE_STR(XWPDEV_UNAVAIL);
CASE_STR(XWPDEV_REG);
CASE_STR(XWPDEV_REGRSP);
CASE_STR(XWPDEV_INVITE);
CASE_STR(XWPDEV_KEEPALIVE);
CASE_STR(XWPDEV_HAVEMSGS);
CASE_STR(XWPDEV_RQSTMSGS);
@ -1756,6 +1779,25 @@ handle_udp_packet( UdpThreadClosure* utc )
}
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_RQSTMSGS: {
DevID devID( ID_TYPE_RELAY );
@ -1988,6 +2030,7 @@ main( int argc, char** argv )
const char* maint_str = NULL;
bool doDaemon = true;
bool doFork = true;
bool doBlock = false;
(void)uptime(); /* force capture of start time */
@ -1999,7 +2042,7 @@ main( int argc, char** argv )
first. */
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" );
if ( opt == -1 ) {
@ -2010,6 +2053,9 @@ main( int argc, char** argv )
case 'h':
usage( argv[0] );
exit( 0 );
case 'b':
doBlock = true;
break;
case 'c':
ctrlport = atoi( optarg );
break;
@ -2160,6 +2206,10 @@ main( int argc, char** argv )
}
#endif
if ( doBlock ) {
DBMgr::Get()->WaitDBConn();
}
if ( -1 != udpport ) {
struct sockaddr_in saddr;
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
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 */
}