mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-02-05 20:45:49 +01:00
Merge branch 'android_branch' into android_groups
Conflicts: xwords4/android/XWords4/res/values/strings.xml xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java
This commit is contained in:
commit
c4e638bd84
35 changed files with 671 additions and 639 deletions
|
@ -129,8 +129,19 @@
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
<data android:scheme="http"
|
<data android:scheme="http"
|
||||||
android:host="eehouse.org" android:pathPrefix="/and" />
|
android:host="@string/invite_host"
|
||||||
|
android:pathPrefix="@string/invite_prefix"
|
||||||
|
/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
|
<!-- <intent-filter> -->
|
||||||
|
<!-- <action android:name="android.intent.action.VIEW" /> -->
|
||||||
|
<!-- <category android:name="android.intent.category.DEFAULT" /> -->
|
||||||
|
<!-- <category android:name="android.intent.category.BROWSABLE" /> -->
|
||||||
|
<!-- <data android:mimeType="*/*" -->
|
||||||
|
<!-- android:scheme="content" -->
|
||||||
|
<!-- /> -->
|
||||||
|
<!-- </intent-filter> -->
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<!-- downloading dicts -->
|
<!-- downloading dicts -->
|
||||||
|
|
|
@ -7,13 +7,18 @@
|
||||||
<body>
|
<body>
|
||||||
<b>Crosswords 4.4 beta 56 release</b>
|
<b>Crosswords 4.4 beta 56 release</b>
|
||||||
<ul>New with this release
|
<ul>New with this release
|
||||||
|
<li>Improve invitations: no more redirection through a website, and
|
||||||
|
confirm before creating duplicate games</li>
|
||||||
|
<li>(For sideloading users only) No more browser involvement in
|
||||||
|
updates: app can launch the installer directly to update
|
||||||
|
itself</li>
|
||||||
|
<li>Remove notifications when their games are deleted</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<ul>Next up
|
<ul>Next up
|
||||||
<li>Make invitations more reliable</li>
|
<li>One more idea for improving invitations</li>
|
||||||
<li>Upgrade app without involving the browser</li>
|
<li>Allow grouping of games in collapsible user-defined categores: "Games with
|
||||||
|
Kati", "Finished games", etc.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p>(The full changelog
|
<p>(The full changelog
|
||||||
|
|
|
@ -30,7 +30,6 @@
|
||||||
<string name="key_clr_bonushint">key_clr_bonushint</string>
|
<string name="key_clr_bonushint">key_clr_bonushint</string>
|
||||||
|
|
||||||
<string name="key_relay_host">key_relay_host</string>
|
<string name="key_relay_host">key_relay_host</string>
|
||||||
<string name="key_redir_host">key_redir_host</string>
|
|
||||||
<string name="key_relay_port">key_relay_port2</string>
|
<string name="key_relay_port">key_relay_port2</string>
|
||||||
<string name="key_update_url">key_update_url</string>
|
<string name="key_update_url">key_update_url</string>
|
||||||
<string name="key_update_prerel">key_update_prerel</string>
|
<string name="key_update_prerel">key_update_prerel</string>
|
||||||
|
@ -103,9 +102,12 @@
|
||||||
<!-- other -->
|
<!-- other -->
|
||||||
<string name="default_host">eehouse.org</string>
|
<string name="default_host">eehouse.org</string>
|
||||||
|
|
||||||
<!-- <string name="default_host">10.0.2.2</string> -->
|
<string name="invite_host">eehouse.org</string>
|
||||||
|
<string name="invite_prefix">/and/</string>
|
||||||
|
<string name="invite_mime">application/x-xwordsinvite</string>
|
||||||
|
<!--string name="invite_mime">text/plain</string-->
|
||||||
|
|
||||||
<string name="dict_url">http://eehouse.org/and_wordlists</string>
|
<string name="dict_url">http://eehouse.org/and_wordlists</string>
|
||||||
<string name="game_url_pathf">//%1$s/and</string>
|
|
||||||
<string name="expl_update_url">Update checks URL</string>
|
<string name="expl_update_url">Update checks URL</string>
|
||||||
<string name="default_update_url">http://eehouse.org/xw4/info.py</string>
|
<string name="default_update_url">http://eehouse.org/xw4/info.py</string>
|
||||||
|
|
||||||
|
|
|
@ -1233,27 +1233,18 @@
|
||||||
encodings for the greater-than and less-than symbols which
|
encodings for the greater-than and less-than symbols which
|
||||||
are not legal in xml strings.)-->
|
are not legal in xml strings.)-->
|
||||||
<string name="invite_htmf">\u003ca href=\"%1$s\"\u003ETap
|
<string name="invite_htmf">\u003ca href=\"%1$s\"\u003ETap
|
||||||
here\u003c/a\u003E (or the raw link below) to accept my invitation and
|
here\u003c/a\u003E (or the full link below) to accept my invitation and
|
||||||
join this game.
|
join this game.
|
||||||
\u003cbr \\\u003E
|
\u003cbr \\\u003E
|
||||||
\u003cbr \\\u003E
|
\u003cbr \\\u003E
|
||||||
(raw link: %1$s)
|
(full link: %1$s)
|
||||||
\u003cbr \\\u003E
|
|
||||||
\u003cbr \\\u003E
|
|
||||||
\u003ca href=\"http://eehouse.org/market_redir.php\"\u003E Tap
|
|
||||||
here\u003c/a\u003E (or the raw link below) to
|
|
||||||
install Crosswords if you haven\'t already.
|
|
||||||
\u003cbr \\\u003E
|
|
||||||
\u003cbr \\\u003E
|
|
||||||
(raw link: http://eehouse.org/market_redir.php)
|
|
||||||
</string>
|
</string>
|
||||||
|
|
||||||
<!-- This is the body of the text version of the invitation. A URL
|
<!-- This is the body of the text version of the invitation. A URL
|
||||||
is created with parameters describing the game and
|
is created with parameters describing the game and
|
||||||
substituted for "%1$s".-->
|
substituted for "%1$s".-->
|
||||||
<string name="invite_txtf">Play Crosswords? Join this game: %1$s
|
<string name="invite_txtf">Let\'s play Crosswords! Join this game:
|
||||||
. (But install Crosswords http://eehouse.org/market_redir.php
|
%1$s .</string>
|
||||||
first if you haven\'t.)</string>
|
|
||||||
|
|
||||||
<!-- When I've created the invitation, in text or html, I ask
|
<!-- When I've created the invitation, in text or html, I ask
|
||||||
Android to launch an app that can send it, typically an email
|
Android to launch an app that can send it, typically an email
|
||||||
|
@ -1440,9 +1431,7 @@
|
||||||
Guest wordlists; Host wins.</string>
|
Guest wordlists; Host wins.</string>
|
||||||
|
|
||||||
|
|
||||||
|
<string name="downloading_dictf">Downloading %s...</string>
|
||||||
<string name="downloading_dictf">Downloading Crosswords
|
|
||||||
wordlist %s...</string>
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
############################################################
|
############################################################
|
||||||
|
@ -1474,9 +1463,10 @@
|
||||||
downloading and not opening the game. This first message
|
downloading and not opening the game. This first message
|
||||||
takes wordlist name and language substituted in for %1$ and
|
takes wordlist name and language substituted in for %1$ and
|
||||||
%2$ -->
|
%2$ -->
|
||||||
<string name="no_dictf">Unable to open game \"%1$s\" because no
|
<string name="no_dictf">You need to download a replacement %2$s
|
||||||
%2$s wordlist found. (It may have been deleted, or stored on
|
wordlist before you can open game \"%1$s\". (The original may have
|
||||||
an external card that is no longer available.)</string>
|
been deleted or stored on an external card that is no longer
|
||||||
|
available.)</string>
|
||||||
|
|
||||||
<!-- This is an alternative message presented when there's also
|
<!-- This is an alternative message presented when there's also
|
||||||
the option of downloading another wordlist. Game name,
|
the option of downloading another wordlist. Game name,
|
||||||
|
@ -1564,8 +1554,8 @@
|
||||||
the same room name over and over so they'll get this warning
|
the same room name over and over so they'll get this warning
|
||||||
and it's harmless to ignore it. -->
|
and it's harmless to ignore it. -->
|
||||||
<string name="dup_game_queryf">You already have a game that seems
|
<string name="dup_game_queryf">You already have a game that seems
|
||||||
to have been created from the same invitation. Are you sure you
|
to have been created (on %1$s) from the same invitation. Are you
|
||||||
want to open another?</string>
|
sure you want to create another?</string>
|
||||||
|
|
||||||
<!-- Title of generic dialog used to display information -->
|
<!-- Title of generic dialog used to display information -->
|
||||||
<string name="info_title">FYI...</string>
|
<string name="info_title">FYI...</string>
|
||||||
|
@ -2127,10 +2117,10 @@
|
||||||
play Crosswords using the wordlist %2$s (for play in %3$s), but it
|
play Crosswords using the wordlist %2$s (for play in %3$s), but it
|
||||||
is not installed. Would you like to download the wordlist or
|
is not installed. Would you like to download the wordlist or
|
||||||
decline the invitation?</string>
|
decline the invitation?</string>
|
||||||
<string name="invite_dict_missing_body_nonamef">You have been invited to
|
<string name="invite_dict_missing_body_nonamef">You have been
|
||||||
play Crosswords using the wordlist %2$s (for play in %3$s), but it
|
invited to play Crosswords using the wordlist %2$s (for play in
|
||||||
is not installed. Would you like to download the wordlist or
|
%3$s), but it is not installed. Would you like to download the
|
||||||
decline the invitation?</string>
|
wordlist?</string>
|
||||||
<string name="button_decline">Decline</string>
|
<string name="button_decline">Decline</string>
|
||||||
|
|
||||||
<string name="downloadingf">Downloading %s...</string>
|
<string name="downloadingf">Downloading %s...</string>
|
||||||
|
|
|
@ -299,6 +299,11 @@
|
||||||
android:summary="Menuitems etc."
|
android:summary="Menuitems etc."
|
||||||
android:defaultValue="false"
|
android:defaultValue="false"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- For broken devices like my Blaze 4G that report a download
|
||||||
|
directory that doesn't exist, allow users to set it. Mine:
|
||||||
|
/sdcard/external_sd/download
|
||||||
|
-->
|
||||||
<org.eehouse.android.xw4.XWEditTextPreference
|
<org.eehouse.android.xw4.XWEditTextPreference
|
||||||
android:key="@string/key_download_path"
|
android:key="@string/key_download_path"
|
||||||
android:title="@string/download_path_title"
|
android:title="@string/download_path_title"
|
||||||
|
@ -324,11 +329,6 @@
|
||||||
android:defaultValue="10998"
|
android:defaultValue="10998"
|
||||||
android:numeric="decimal"
|
android:numeric="decimal"
|
||||||
/>
|
/>
|
||||||
<org.eehouse.android.xw4.XWEditTextPreference
|
|
||||||
android:key="@string/key_redir_host"
|
|
||||||
android:title="@string/redir_host"
|
|
||||||
android:defaultValue="@string/default_host"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<org.eehouse.android.xw4.XWEditTextPreference
|
<org.eehouse.android.xw4.XWEditTextPreference
|
||||||
android:key="@string/key_dict_host"
|
android:key="@string/key_dict_host"
|
||||||
|
|
|
@ -444,7 +444,7 @@ public class BTService extends Service {
|
||||||
result = BTCmd.INVITE_ACCPT;
|
result = BTCmd.INVITE_ACCPT;
|
||||||
String body = Utils.format( BTService.this,
|
String body = Utils.format( BTService.this,
|
||||||
R.string.new_bt_bodyf, sender );
|
R.string.new_bt_bodyf, sender );
|
||||||
postNotification( gameID, R.string.new_bt_title, body );
|
postNotification( gameID, R.string.new_bt_title, body, rowid );
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result = BTCmd.INVITE_DUPID;
|
result = BTCmd.INVITE_DUPID;
|
||||||
|
@ -497,7 +497,7 @@ public class BTService extends Service {
|
||||||
buffer, addr,
|
buffer, addr,
|
||||||
m_btMsgSink ) ) {
|
m_btMsgSink ) ) {
|
||||||
postNotification( gameID, R.string.new_btmove_title,
|
postNotification( gameID, R.string.new_btmove_title,
|
||||||
R.string.new_move_body );
|
R.string.new_move_body, rowid );
|
||||||
// do nothing
|
// do nothing
|
||||||
} else {
|
} else {
|
||||||
DbgUtils.logf( "nobody took msg for gameID %X",
|
DbgUtils.logf( "nobody took msg for gameID %X",
|
||||||
|
@ -967,17 +967,17 @@ public class BTService extends Service {
|
||||||
return dos;
|
return dos;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void postNotification( int gameID, int title, int body )
|
private void postNotification( int gameID, int title, int body, long rowid )
|
||||||
{
|
{
|
||||||
postNotification( gameID, title, getString( body ) );
|
postNotification( gameID, title, getString( body ), rowid );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void postNotification( int gameID, int title, String body )
|
private void postNotification( int gameID, int title, String body,
|
||||||
|
long rowid )
|
||||||
{
|
{
|
||||||
Intent intent = new Intent( this, DispatchNotify.class );
|
Intent intent = GamesList.makeGameIDIntent( this, gameID );
|
||||||
intent.putExtra( DispatchNotify.GAMEID_EXTRA, gameID );
|
|
||||||
Utils.postNotification( this, intent, R.string.new_btmove_title,
|
Utils.postNotification( this, intent, R.string.new_btmove_title,
|
||||||
body, gameID );
|
body, (int)rowid );
|
||||||
}
|
}
|
||||||
|
|
||||||
private Thread killSocketIn( final BluetoothSocket socket )
|
private Thread killSocketIn( final BluetoothSocket socket )
|
||||||
|
|
|
@ -57,7 +57,7 @@ import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole;
|
||||||
|
|
||||||
public class BoardActivity extends XWActivity
|
public class BoardActivity extends XWActivity
|
||||||
implements TransportProcs.TPMsgHandler, View.OnClickListener,
|
implements TransportProcs.TPMsgHandler, View.OnClickListener,
|
||||||
NetUtils.DownloadFinishedListener {
|
DictImportActivity.DownloadFinishedListener {
|
||||||
|
|
||||||
public static final String INTENT_KEY_CHAT = "chat";
|
public static final String INTENT_KEY_CHAT = "chat";
|
||||||
|
|
||||||
|
@ -167,7 +167,7 @@ public class BoardActivity extends XWActivity
|
||||||
private boolean m_haveInvited = false;
|
private boolean m_haveInvited = false;
|
||||||
|
|
||||||
private static BoardActivity s_this = null;
|
private static BoardActivity s_this = null;
|
||||||
private static Object s_thisLocker = new Object();
|
private static Class s_thisLocker = BoardActivity.class;
|
||||||
|
|
||||||
public static boolean feedMessage( int gameID, byte[] msg,
|
public static boolean feedMessage( int gameID, byte[] msg,
|
||||||
CommsAddrRec retAddr )
|
CommsAddrRec retAddr )
|
||||||
|
@ -259,10 +259,11 @@ public class BoardActivity extends XWActivity
|
||||||
if ( DLG_USEDICT == id ) {
|
if ( DLG_USEDICT == id ) {
|
||||||
setGotGameDict( m_getDict );
|
setGotGameDict( m_getDict );
|
||||||
} else {
|
} else {
|
||||||
NetUtils.downloadDictInBack( BoardActivity.this,
|
DictImportActivity
|
||||||
m_gi.dictLang,
|
.downloadDictInBack( BoardActivity.this,
|
||||||
m_getDict,
|
m_gi.dictLang,
|
||||||
BoardActivity.this );
|
m_getDict,
|
||||||
|
BoardActivity.this );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1051,7 +1052,7 @@ public class BoardActivity extends XWActivity
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////
|
//////////////////////////////////////////////////
|
||||||
// NetUtils.DownloadFinishedListener interface
|
// DictImportActivity.DownloadFinishedListener interface
|
||||||
//////////////////////////////////////////////////
|
//////////////////////////////////////////////////
|
||||||
public void downloadFinished( final String name, final boolean success )
|
public void downloadFinished( final String name, final boolean success )
|
||||||
{
|
{
|
||||||
|
@ -1731,7 +1732,7 @@ public class BoardActivity extends XWActivity
|
||||||
if ( null != m_xport ) {
|
if ( null != m_xport ) {
|
||||||
warnIfNoTransport();
|
warnIfNoTransport();
|
||||||
trySendChats();
|
trySendChats();
|
||||||
removeNotifications();
|
Utils.cancelNotification( this, (int)m_rowid );
|
||||||
m_xport.tickle( m_connType );
|
m_xport.tickle( m_connType );
|
||||||
tryInvites();
|
tryInvites();
|
||||||
}
|
}
|
||||||
|
@ -1922,26 +1923,6 @@ public class BoardActivity extends XWActivity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeNotifications()
|
|
||||||
{
|
|
||||||
int id = 0;
|
|
||||||
switch( m_connType ) {
|
|
||||||
case COMMS_CONN_BT:
|
|
||||||
case COMMS_CONN_SMS:
|
|
||||||
id = m_gi.gameID;
|
|
||||||
break;
|
|
||||||
case COMMS_CONN_RELAY:
|
|
||||||
String relayID = DBUtils.getRelayID( this, m_rowid );
|
|
||||||
if ( null != relayID ) {
|
|
||||||
id = relayID.hashCode();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ( 0 != id ) {
|
|
||||||
Utils.cancelNotification( this, id );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void tryInvites()
|
private void tryInvites()
|
||||||
{
|
{
|
||||||
if ( XWApp.BTSUPPORTED || XWApp.SMSSUPPORTED ) {
|
if ( XWApp.BTSUPPORTED || XWApp.SMSSUPPORTED ) {
|
||||||
|
|
|
@ -126,7 +126,7 @@ public class ConnStatusHandler {
|
||||||
|
|
||||||
private static HashMap<CommsConnType,SuccessRecord[]> s_records =
|
private static HashMap<CommsConnType,SuccessRecord[]> s_records =
|
||||||
new HashMap<CommsConnType,SuccessRecord[]>();
|
new HashMap<CommsConnType,SuccessRecord[]>();
|
||||||
private static Object s_lockObj = new Object();
|
private static Class s_lockObj = ConnStatusHandler.class;
|
||||||
private static boolean s_needsSave = false;
|
private static boolean s_needsSave = false;
|
||||||
|
|
||||||
public static void setRect( int left, int top, int right, int bottom )
|
public static void setRect( int left, int top, int right, int bottom )
|
||||||
|
|
|
@ -141,7 +141,7 @@ public class DBHelper extends SQLiteOpenHelper {
|
||||||
|
|
||||||
private static final String[] s_groupsSchema = {
|
private static final String[] s_groupsSchema = {
|
||||||
GROUPNAME, "TEXT"
|
GROUPNAME, "TEXT"
|
||||||
,EXPANDED, "INTEGER(0)"
|
,EXPANDED, "INTEGER(1)"
|
||||||
};
|
};
|
||||||
|
|
||||||
public DBHelper( Context context )
|
public DBHelper( Context context )
|
||||||
|
|
|
@ -535,13 +535,16 @@ public class DBUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long getRowIDForOpen( Context context, NetLaunchInfo nli )
|
// Return creation time of newest game matching this nli, or null
|
||||||
|
// if none found.
|
||||||
|
public static Date getMostRecentCreate( Context context,
|
||||||
|
NetLaunchInfo nli )
|
||||||
{
|
{
|
||||||
long result = ROWID_NOTFOUND;
|
Date result = null;
|
||||||
initDB( context );
|
initDB( context );
|
||||||
synchronized( s_dbHelper ) {
|
synchronized( s_dbHelper ) {
|
||||||
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
|
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
|
||||||
String[] columns = { ROW_ID };
|
String[] columns = { DBHelper.CREATE_TIME };
|
||||||
String selection =
|
String selection =
|
||||||
String.format( "%s='%s' AND %s='%s' AND %s=%d AND %s=%d",
|
String.format( "%s='%s' AND %s='%s' AND %s=%d AND %s=%d",
|
||||||
DBHelper.ROOMNAME, nli.room,
|
DBHelper.ROOMNAME, nli.room,
|
||||||
|
@ -549,9 +552,11 @@ public class DBUtils {
|
||||||
DBHelper.DICTLANG, nli.lang,
|
DBHelper.DICTLANG, nli.lang,
|
||||||
DBHelper.NUM_PLAYERS, nli.nPlayersT );
|
DBHelper.NUM_PLAYERS, nli.nPlayersT );
|
||||||
Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
|
Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
|
||||||
selection, null, null, null, null );
|
selection, null, null, null,
|
||||||
if ( 1 == cursor.getCount() && cursor.moveToFirst() ) {
|
DBHelper.CREATE_TIME + " DESC" ); // order by
|
||||||
result = cursor.getLong( cursor.getColumnIndex(ROW_ID) );
|
if ( cursor.moveToNext() ) {
|
||||||
|
int indx = cursor.getColumnIndex( DBHelper.CREATE_TIME );
|
||||||
|
result = new Date( cursor.getLong( indx ) );
|
||||||
}
|
}
|
||||||
cursor.close();
|
cursor.close();
|
||||||
db.close();
|
db.close();
|
||||||
|
@ -559,14 +564,14 @@ public class DBUtils {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long getRowIDForOpen( Context context, Uri data )
|
public static Date getMostRecentCreate( Context context, Uri data )
|
||||||
{
|
{
|
||||||
long rowid = ROWID_NOTFOUND;
|
Date result = null;
|
||||||
NetLaunchInfo nli = new NetLaunchInfo( data );
|
NetLaunchInfo nli = new NetLaunchInfo( context, data );
|
||||||
if ( null != nli && nli.isValid() ) {
|
if ( null != nli && nli.isValid() ) {
|
||||||
rowid = getRowIDForOpen( context, nli );
|
result = getMostRecentCreate( context, nli );
|
||||||
}
|
}
|
||||||
return rowid;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String[] getRelayIDs( Context context, boolean noMsgs )
|
public static String[] getRelayIDs( Context context, boolean noMsgs )
|
||||||
|
@ -704,34 +709,20 @@ public class DBUtils {
|
||||||
{
|
{
|
||||||
Assert.assertTrue( lock.canWrite() );
|
Assert.assertTrue( lock.canWrite() );
|
||||||
long rowid = lock.getRowid();
|
long rowid = lock.getRowid();
|
||||||
initDB( context );
|
|
||||||
synchronized( s_dbHelper ) {
|
|
||||||
SQLiteDatabase db = s_dbHelper.getWritableDatabase();
|
|
||||||
|
|
||||||
String selection = String.format( ROW_ID_FMT, rowid );
|
ContentValues values = new ContentValues();
|
||||||
ContentValues values = new ContentValues();
|
values.put( DBHelper.SNAPSHOT, bytes );
|
||||||
values.put( DBHelper.SNAPSHOT, bytes );
|
|
||||||
|
|
||||||
long timestamp = new Date().getTime();
|
long timestamp = new Date().getTime();
|
||||||
if ( setCreate ) {
|
if ( setCreate ) {
|
||||||
values.put( DBHelper.CREATE_TIME, timestamp );
|
values.put( DBHelper.CREATE_TIME, timestamp );
|
||||||
}
|
|
||||||
values.put( DBHelper.LASTPLAY_TIME, timestamp );
|
|
||||||
|
|
||||||
int result = db.update( DBHelper.TABLE_NAME_SUM,
|
|
||||||
values, selection, null );
|
|
||||||
if ( 0 == result ) {
|
|
||||||
Assert.fail();
|
|
||||||
// values.put( DBHelper.FILE_NAME, path );
|
|
||||||
// rowid = db.insert( DBHelper.TABLE_NAME_SUM, null, values );
|
|
||||||
// DbgUtils.logf( "insert=>%d", rowid );
|
|
||||||
// Assert.assertTrue( row >= 0 );
|
|
||||||
}
|
|
||||||
db.close();
|
|
||||||
}
|
}
|
||||||
setCached( rowid, null ); // force reread
|
values.put( DBHelper.LASTPLAY_TIME, timestamp );
|
||||||
|
|
||||||
if ( -1 != rowid ) {
|
updateRow( context, DBHelper.TABLE_NAME_SUM, rowid, values );
|
||||||
|
|
||||||
|
setCached( rowid, null ); // force reread
|
||||||
|
if ( -1 != rowid ) { // Is this possible? PENDING
|
||||||
notifyListeners( rowid );
|
notifyListeners( rowid );
|
||||||
}
|
}
|
||||||
return rowid;
|
return rowid;
|
||||||
|
@ -1370,25 +1361,14 @@ public class DBUtils {
|
||||||
private static void saveChatHistory( Context context, long rowid,
|
private static void saveChatHistory( Context context, long rowid,
|
||||||
String history )
|
String history )
|
||||||
{
|
{
|
||||||
initDB( context );
|
ContentValues values = new ContentValues();
|
||||||
synchronized( s_dbHelper ) {
|
if ( null != history ) {
|
||||||
SQLiteDatabase db = s_dbHelper.getWritableDatabase();
|
values.put( DBHelper.CHAT_HISTORY, history );
|
||||||
|
} else {
|
||||||
String selection = String.format( ROW_ID_FMT, rowid );
|
values.putNull( DBHelper.CHAT_HISTORY );
|
||||||
ContentValues values = new ContentValues();
|
|
||||||
if ( null != history ) {
|
|
||||||
values.put( DBHelper.CHAT_HISTORY, history );
|
|
||||||
} else {
|
|
||||||
values.putNull( DBHelper.CHAT_HISTORY );
|
|
||||||
}
|
|
||||||
|
|
||||||
long timestamp = new Date().getTime();
|
|
||||||
values.put( DBHelper.LASTPLAY_TIME, timestamp );
|
|
||||||
|
|
||||||
int result = db.update( DBHelper.TABLE_NAME_SUM,
|
|
||||||
values, selection, null );
|
|
||||||
db.close();
|
|
||||||
}
|
}
|
||||||
|
values.put( DBHelper.LASTPLAY_TIME, new Date().getTime() );
|
||||||
|
updateRow( context, DBHelper.TABLE_NAME_SUM, rowid, values );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void initDB( Context context )
|
private static void initDB( Context context )
|
||||||
|
@ -1401,6 +1381,23 @@ public class DBUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void updateRow( Context context, String table,
|
||||||
|
long rowid, ContentValues values )
|
||||||
|
{
|
||||||
|
initDB( context );
|
||||||
|
synchronized( s_dbHelper ) {
|
||||||
|
SQLiteDatabase db = s_dbHelper.getWritableDatabase();
|
||||||
|
|
||||||
|
String selection = String.format( ROW_ID_FMT, rowid );
|
||||||
|
|
||||||
|
int result = db.update( table, values, selection, null );
|
||||||
|
db.close();
|
||||||
|
if ( 0 == result ) {
|
||||||
|
DbgUtils.logf( "updateRow failed" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void notifyListeners( long rowid )
|
private static void notifyListeners( long rowid )
|
||||||
{
|
{
|
||||||
synchronized( s_listeners ) {
|
synchronized( s_listeners ) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
|
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
|
||||||
/*
|
/*
|
||||||
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
|
* Copyright 2009-2012 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
|
||||||
|
@ -21,6 +21,7 @@
|
||||||
package org.eehouse.android.xw4;
|
package org.eehouse.android.xw4;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
@ -32,15 +33,37 @@ import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
import junit.framework.Assert;
|
import junit.framework.Assert;
|
||||||
|
|
||||||
public class DictImportActivity extends XWActivity {
|
public class DictImportActivity extends XWActivity {
|
||||||
|
|
||||||
public static final String APK_EXTRA = "APK";
|
// URIs coming in in intents
|
||||||
|
private static final String APK_EXTRA = "APK";
|
||||||
|
private static final String DICT_EXTRA = "XWD";
|
||||||
|
|
||||||
|
public interface DownloadFinishedListener {
|
||||||
|
void downloadFinished( String name, boolean success );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Track callbacks for downloads.
|
||||||
|
private static class ListenerData {
|
||||||
|
public ListenerData( String dictName, DownloadFinishedListener lstnr )
|
||||||
|
{
|
||||||
|
m_dictName = dictName;
|
||||||
|
m_lstnr = lstnr;
|
||||||
|
}
|
||||||
|
public String m_dictName;
|
||||||
|
public DownloadFinishedListener m_lstnr;
|
||||||
|
}
|
||||||
|
private static HashMap<String,ListenerData> s_listeners =
|
||||||
|
new HashMap<String,ListenerData>();
|
||||||
|
|
||||||
private class DownloadFilesTask extends AsyncTask<Uri, Integer, Long> {
|
private class DownloadFilesTask extends AsyncTask<Uri, Integer, Long> {
|
||||||
private String m_saved = null;
|
private String m_savedDict = null;
|
||||||
|
private String m_url = null;
|
||||||
private boolean m_isApp = false;
|
private boolean m_isApp = false;
|
||||||
private File m_appFile = null;
|
private File m_appFile = null;
|
||||||
|
|
||||||
|
@ -50,10 +73,16 @@ public class DictImportActivity extends XWActivity {
|
||||||
m_isApp = isApp;
|
m_isApp = isApp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DownloadFilesTask( String url, boolean isApp )
|
||||||
|
{
|
||||||
|
this( isApp );
|
||||||
|
m_url = url;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Long doInBackground( Uri... uris )
|
protected Long doInBackground( Uri... uris )
|
||||||
{
|
{
|
||||||
m_saved = null;
|
m_savedDict = null;
|
||||||
m_appFile = null;
|
m_appFile = null;
|
||||||
|
|
||||||
int count = uris.length;
|
int count = uris.length;
|
||||||
|
@ -71,7 +100,7 @@ public class DictImportActivity extends XWActivity {
|
||||||
if ( m_isApp ) {
|
if ( m_isApp ) {
|
||||||
m_appFile = saveToDownloads( is, name );
|
m_appFile = saveToDownloads( is, name );
|
||||||
} else {
|
} else {
|
||||||
m_saved = saveDict( is, name );
|
m_savedDict = saveDict( is, name );
|
||||||
}
|
}
|
||||||
is.close();
|
is.close();
|
||||||
} catch ( java.net.URISyntaxException use ) {
|
} catch ( java.net.URISyntaxException use ) {
|
||||||
|
@ -89,15 +118,19 @@ public class DictImportActivity extends XWActivity {
|
||||||
protected void onPostExecute( Long result )
|
protected void onPostExecute( Long result )
|
||||||
{
|
{
|
||||||
DbgUtils.logf( "onPostExecute passed %d", result );
|
DbgUtils.logf( "onPostExecute passed %d", result );
|
||||||
if ( null != m_saved ) {
|
if ( null != m_savedDict ) {
|
||||||
DictUtils.DictLoc loc =
|
DictUtils.DictLoc loc =
|
||||||
XWPrefs.getDefaultLoc( DictImportActivity.this );
|
XWPrefs.getDefaultLoc( DictImportActivity.this );
|
||||||
DictLangCache.inval( DictImportActivity.this, m_saved,
|
DictLangCache.inval( DictImportActivity.this, m_savedDict,
|
||||||
loc, true );
|
loc, true );
|
||||||
|
callListener( m_url, true );
|
||||||
} else if ( null != m_appFile ) {
|
} else if ( null != m_appFile ) {
|
||||||
// launch the installer
|
// launch the installer
|
||||||
Intent intent = Utils.makeInstallIntent( m_appFile );
|
Intent intent = Utils.makeInstallIntent( m_appFile );
|
||||||
startActivity( intent );
|
startActivity( intent );
|
||||||
|
} else {
|
||||||
|
// we failed at something....
|
||||||
|
callListener( m_url, false );
|
||||||
}
|
}
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
@ -120,24 +153,29 @@ public class DictImportActivity extends XWActivity {
|
||||||
Uri uri = intent.getData();
|
Uri uri = intent.getData();
|
||||||
if ( null == uri ) {
|
if ( null == uri ) {
|
||||||
String url = intent.getStringExtra( APK_EXTRA );
|
String url = intent.getStringExtra( APK_EXTRA );
|
||||||
|
boolean isApp = null != url;
|
||||||
|
if ( !isApp ) {
|
||||||
|
url = intent.getStringExtra( DICT_EXTRA );
|
||||||
|
}
|
||||||
if ( null != url ) {
|
if ( null != url ) {
|
||||||
dft = new DownloadFilesTask( true );
|
dft = new DownloadFilesTask( url, isApp );
|
||||||
uri = Uri.parse(url);
|
uri = Uri.parse( url );
|
||||||
}
|
}
|
||||||
} else if ( null != intent.getType()
|
} else if ( null != intent.getType()
|
||||||
&& intent.getType().equals( "application/x-xwordsdict" ) ) {
|
&& intent.getType().equals( "application/x-xwordsdict" ) ) {
|
||||||
dft = new DownloadFilesTask( false );
|
dft = new DownloadFilesTask( false );
|
||||||
} else if ( uri.toString().endsWith( XWConstants.DICT_EXTN ) ) {
|
} else if ( uri.toString().endsWith( XWConstants.DICT_EXTN ) ) {
|
||||||
String txt = getString( R.string.downloading_dictf,
|
dft = new DownloadFilesTask( uri.toString(), false );
|
||||||
basename( uri.getPath()) );
|
|
||||||
TextView view = (TextView)findViewById( R.id.dwnld_message );
|
|
||||||
view.setText( txt );
|
|
||||||
dft = new DownloadFilesTask( false );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( null == dft ) {
|
if ( null == dft ) {
|
||||||
finish();
|
finish();
|
||||||
} else {
|
} else {
|
||||||
|
String showName = basename( uri.getPath() );
|
||||||
|
String msg = getString( R.string.downloading_dictf, showName );
|
||||||
|
TextView view = (TextView)findViewById( R.id.dwnld_message );
|
||||||
|
view.setText( msg );
|
||||||
|
|
||||||
dft.execute( uri );
|
dft.execute( uri );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,8 +184,7 @@ public class DictImportActivity extends XWActivity {
|
||||||
{
|
{
|
||||||
boolean success = false;
|
boolean success = false;
|
||||||
File appFile = new File( DictUtils.getDownloadDir( this ), name );
|
File appFile = new File( DictUtils.getDownloadDir( this ), name );
|
||||||
Assert.assertNotNull( appFile );
|
|
||||||
|
|
||||||
byte[] buf = new byte[1024*4];
|
byte[] buf = new byte[1024*4];
|
||||||
try {
|
try {
|
||||||
FileOutputStream fos = new FileOutputStream( appFile );
|
FileOutputStream fos = new FileOutputStream( appFile );
|
||||||
|
@ -183,6 +220,57 @@ public class DictImportActivity extends XWActivity {
|
||||||
{
|
{
|
||||||
return new File(path).getName();
|
return new File(path).getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void rememberListener( String url, String name,
|
||||||
|
DownloadFinishedListener lstnr )
|
||||||
|
{
|
||||||
|
ListenerData ld = new ListenerData( name, lstnr );
|
||||||
|
synchronized( s_listeners ) {
|
||||||
|
s_listeners.put( url, ld );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void callListener( String url, boolean success )
|
||||||
|
{
|
||||||
|
if ( null != url ) {
|
||||||
|
ListenerData ld;
|
||||||
|
synchronized( s_listeners ) {
|
||||||
|
ld = s_listeners.get( url );
|
||||||
|
if ( null != ld ) {
|
||||||
|
s_listeners.remove( url );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( null != ld ) {
|
||||||
|
ld.m_lstnr.downloadFinished( ld.m_dictName, success );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void downloadDictInBack( Context context, int lang,
|
||||||
|
String name,
|
||||||
|
DownloadFinishedListener lstnr )
|
||||||
|
{
|
||||||
|
String url = Utils.makeDictUrl( context, lang, name );
|
||||||
|
if ( null != lstnr ) {
|
||||||
|
rememberListener( url, name, lstnr );
|
||||||
|
}
|
||||||
|
downloadDictInBack( context, url );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void downloadDictInBack( Context context, String url )
|
||||||
|
{
|
||||||
|
Intent intent = new Intent( context, DictImportActivity.class );
|
||||||
|
intent.putExtra( DICT_EXTRA, url );
|
||||||
|
context.startActivity( intent );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Intent makeAppDownloadIntent( Context context, String url )
|
||||||
|
{
|
||||||
|
Intent intent = new Intent( context, DictImportActivity.class );
|
||||||
|
intent.putExtra( APK_EXTRA, url );
|
||||||
|
return intent;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ import org.eehouse.android.xw4.DictUtils.DictLoc;
|
||||||
public class DictsActivity extends ExpandableListActivity
|
public class DictsActivity extends ExpandableListActivity
|
||||||
implements View.OnClickListener, XWListItem.DeleteCallback,
|
implements View.OnClickListener, XWListItem.DeleteCallback,
|
||||||
MountEventReceiver.SDCardNotifiee, DlgDelegate.DlgClickNotify,
|
MountEventReceiver.SDCardNotifiee, DlgDelegate.DlgClickNotify,
|
||||||
NetUtils.DownloadFinishedListener {
|
DictImportActivity.DownloadFinishedListener {
|
||||||
|
|
||||||
private static final String DICT_DOLAUNCH = "do_launch";
|
private static final String DICT_DOLAUNCH = "do_launch";
|
||||||
private static final String DICT_LANG_EXTRA = "use_lang";
|
private static final String DICT_LANG_EXTRA = "use_lang";
|
||||||
|
@ -339,8 +339,9 @@ public class DictsActivity extends ExpandableListActivity
|
||||||
String name = intent.getStringExtra( MultiService.DICT );
|
String name = intent.getStringExtra( MultiService.DICT );
|
||||||
m_launchedForMissing = true;
|
m_launchedForMissing = true;
|
||||||
m_handler = new Handler();
|
m_handler = new Handler();
|
||||||
NetUtils.downloadDictInBack( DictsActivity.this, lang,
|
DictImportActivity
|
||||||
name, DictsActivity.this );
|
.downloadDictInBack( DictsActivity.this, lang,
|
||||||
|
name, DictsActivity.this );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
lstnr2 = new OnClickListener() {
|
lstnr2 = new OnClickListener() {
|
||||||
|
@ -555,10 +556,9 @@ public class DictsActivity extends ExpandableListActivity
|
||||||
{
|
{
|
||||||
int loci = intent.getIntExtra( UpdateCheckReceiver.NEW_DICT_LOC, 0 );
|
int loci = intent.getIntExtra( UpdateCheckReceiver.NEW_DICT_LOC, 0 );
|
||||||
if ( 0 < loci ) {
|
if ( 0 < loci ) {
|
||||||
DictLoc loc = DictLoc.values()[loci];
|
|
||||||
String url =
|
String url =
|
||||||
intent.getStringExtra( UpdateCheckReceiver.NEW_DICT_URL );
|
intent.getStringExtra( UpdateCheckReceiver.NEW_DICT_URL );
|
||||||
NetUtils.downloadDictInBack( this, url, loc, null );
|
DictImportActivity.downloadDictInBack( this, url );
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -769,7 +769,7 @@ public class DictsActivity extends ExpandableListActivity
|
||||||
launchAndDownload( activity, 0, null );
|
launchAndDownload( activity, 0, null );
|
||||||
}
|
}
|
||||||
|
|
||||||
// NetUtils.DownloadFinishedListener interface
|
// DictImportActivity.DownloadFinishedListener interface
|
||||||
public void downloadFinished( String name, final boolean success )
|
public void downloadFinished( String name, final boolean success )
|
||||||
{
|
{
|
||||||
if ( m_launchedForMissing ) {
|
if ( m_launchedForMissing ) {
|
||||||
|
|
|
@ -33,175 +33,16 @@ import org.eehouse.android.xw4.jni.GameSummary;
|
||||||
|
|
||||||
public class DispatchNotify extends Activity {
|
public class DispatchNotify extends Activity {
|
||||||
|
|
||||||
public static final String RELAYIDS_EXTRA = "relayids";
|
|
||||||
public static final String GAMEID_EXTRA = "gameid";
|
|
||||||
|
|
||||||
public interface HandleRelaysIface {
|
|
||||||
void handleRelaysIDs( final String[] relayIDs );
|
|
||||||
void handleInvite( final Uri invite );
|
|
||||||
void handleGameID( int gameID );
|
|
||||||
}
|
|
||||||
|
|
||||||
private static HashSet<HandleRelaysIface> s_running =
|
|
||||||
new HashSet<HandleRelaysIface>();
|
|
||||||
private static HandleRelaysIface s_handler;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate( Bundle savedInstanceState )
|
protected void onCreate( Bundle savedInstanceState )
|
||||||
{
|
{
|
||||||
boolean mustLaunch = false;
|
|
||||||
super.onCreate( savedInstanceState );
|
super.onCreate( savedInstanceState );
|
||||||
|
|
||||||
String[] relayIDs = getIntent().getStringArrayExtra( RELAYIDS_EXTRA );
|
|
||||||
int gameID = getIntent().getIntExtra( GAMEID_EXTRA, -1 );
|
|
||||||
Uri data = getIntent().getData();
|
Uri data = getIntent().getData();
|
||||||
|
if ( null != data ) { // relay invite redirected URL case
|
||||||
if ( null != relayIDs ) {
|
GamesList.openGame( this, data );
|
||||||
if ( !tryHandle( relayIDs ) ) {
|
|
||||||
mustLaunch = true;
|
|
||||||
}
|
|
||||||
} else if ( -1 != gameID ) {
|
|
||||||
if ( !tryHandle( gameID ) ) {
|
|
||||||
mustLaunch = true;
|
|
||||||
}
|
|
||||||
} else if ( null != data ) { // relay invite redirected URL case
|
|
||||||
NetLaunchInfo nli = new NetLaunchInfo( data );
|
|
||||||
if ( null != nli && nli.isValid() ) {
|
|
||||||
long rowid = DBUtils.getRowIDForOpen( this, nli );
|
|
||||||
if ( DBUtils.ROWID_NOTFOUND == rowid ) {
|
|
||||||
boolean haveDict;
|
|
||||||
if ( null == nli.dict ) { // can only test for language support
|
|
||||||
haveDict =
|
|
||||||
0 < DictLangCache.getHaveLang( this,
|
|
||||||
nli.lang ).length;
|
|
||||||
} else {
|
|
||||||
haveDict =
|
|
||||||
DictLangCache.haveDict( this, nli.lang, nli.dict );
|
|
||||||
}
|
|
||||||
if ( haveDict ) {
|
|
||||||
if ( !tryHandle( data ) ) {
|
|
||||||
mustLaunch = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Intent intent =
|
|
||||||
MultiService.makeMissingDictIntent( this, nli );
|
|
||||||
intent.putExtra( MultiService.OWNER,
|
|
||||||
MultiService.OWNER_RELAY );
|
|
||||||
// do we have gameID?
|
|
||||||
MultiService.
|
|
||||||
postMissingDictNotification( this, intent,
|
|
||||||
nli.inviteID
|
|
||||||
.hashCode() );
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DbgUtils.logf( "DispatchNotify: dropping duplicate invite" );
|
|
||||||
GameSummary summary = DBUtils.getSummary( this, rowid );
|
|
||||||
if ( null != summary ) {
|
|
||||||
gameID = summary.gameID;
|
|
||||||
if ( !tryHandle( gameID ) ) {
|
|
||||||
mustLaunch = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( mustLaunch ) {
|
|
||||||
DbgUtils.logf( "DispatchNotify: nothing running" );
|
|
||||||
Intent intent = new Intent( this, GamesList.class );
|
|
||||||
|
|
||||||
// This combination of flags will bring an existing
|
|
||||||
// GamesList instance to the front, killing any children
|
|
||||||
// it has, or create a new one if none exists. Coupled
|
|
||||||
// with a "standard" launchMode it seems to work, meaning
|
|
||||||
// both that the app preserves its stack in normal use
|
|
||||||
// (you can go to Home with a stack of activities and
|
|
||||||
// return to the top activity on that stack if you
|
|
||||||
// relaunch the app) and that when I launch from here the
|
|
||||||
// stack gets nuked and we don't get a second GamesList
|
|
||||||
// instance.
|
|
||||||
|
|
||||||
intent.setFlags( Intent.FLAG_ACTIVITY_CLEAR_TOP
|
|
||||||
| Intent.FLAG_ACTIVITY_NEW_TASK );
|
|
||||||
if ( null != relayIDs ) {
|
|
||||||
intent.putExtra( RELAYIDS_EXTRA, relayIDs );
|
|
||||||
} else if ( -1 != gameID ) {
|
|
||||||
intent.putExtra( GAMEID_EXTRA, gameID );
|
|
||||||
} else if ( null != data ) {
|
|
||||||
intent.setData( data );
|
|
||||||
} else {
|
|
||||||
Assert.fail();
|
|
||||||
}
|
|
||||||
startActivity( intent );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
finish();
|
finish();
|
||||||
}
|
} // onCreate
|
||||||
|
|
||||||
public static void SetRunning( Activity running )
|
|
||||||
{
|
|
||||||
if ( running instanceof HandleRelaysIface ) {
|
|
||||||
s_running.add( (HandleRelaysIface)running );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void ClearRunning( Activity running )
|
|
||||||
{
|
|
||||||
if ( running instanceof HandleRelaysIface ) {
|
|
||||||
s_running.remove( (HandleRelaysIface)running );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetRelayIDsHandler( HandleRelaysIface iface )
|
|
||||||
{
|
|
||||||
s_handler = iface;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean tryHandle( Uri data )
|
|
||||||
{
|
|
||||||
boolean handled = false;
|
|
||||||
if ( null != s_handler ) {
|
|
||||||
// This means the GamesList activity is frontmost
|
|
||||||
s_handler.handleInvite( data );
|
|
||||||
handled = true;
|
|
||||||
} else {
|
|
||||||
for ( HandleRelaysIface iface : s_running ) {
|
|
||||||
iface.handleInvite( data );
|
|
||||||
handled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return handled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean tryHandle( String[] relayIDs )
|
|
||||||
{
|
|
||||||
boolean handled = false;
|
|
||||||
if ( null != s_handler ) {
|
|
||||||
// This means the GamesList activity is frontmost
|
|
||||||
s_handler.handleRelaysIDs( relayIDs );
|
|
||||||
handled = true;
|
|
||||||
} else {
|
|
||||||
for ( HandleRelaysIface iface : s_running ) {
|
|
||||||
iface.handleRelaysIDs( relayIDs );
|
|
||||||
handled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return handled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean tryHandle( int gameID )
|
|
||||||
{
|
|
||||||
boolean handled = false;
|
|
||||||
if ( null != s_handler ) {
|
|
||||||
// This means the GamesList activity is frontmost
|
|
||||||
s_handler.handleGameID( gameID );
|
|
||||||
handled = true;
|
|
||||||
} else {
|
|
||||||
for ( HandleRelaysIface iface : s_running ) {
|
|
||||||
iface.handleGameID( gameID );
|
|
||||||
handled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return handled;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,18 @@ public class GCMIntentService extends GCMBaseIntentService {
|
||||||
@Override
|
@Override
|
||||||
protected void onMessage( Context context, Intent intent )
|
protected void onMessage( Context context, Intent intent )
|
||||||
{
|
{
|
||||||
String value = intent.getStringExtra( "msg" );
|
String value;
|
||||||
|
|
||||||
|
value = intent.getStringExtra( "getMoves" );
|
||||||
|
if ( null != value && Boolean.parseBoolean( value ) ) {
|
||||||
|
RelayReceiver.RestartTimer( context, true );
|
||||||
|
}
|
||||||
|
value = intent.getStringExtra( "checkUpdates" );
|
||||||
|
if ( null != value && Boolean.parseBoolean( value ) ) {
|
||||||
|
UpdateCheckReceiver.checkVersions( context, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
value = intent.getStringExtra( "msg" );
|
||||||
if ( null != value ) {
|
if ( null != value ) {
|
||||||
String title = intent.getStringExtra( "title" );
|
String title = intent.getStringExtra( "title" );
|
||||||
if ( null != title ) {
|
if ( null != title ) {
|
||||||
|
@ -64,11 +75,6 @@ public class GCMIntentService extends GCMBaseIntentService {
|
||||||
Utils.postNotification( context, null, title, value, code );
|
Utils.postNotification( context, null, title, value, code );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
value = intent.getStringExtra( "getMoves" );
|
|
||||||
if ( null != value && Boolean.parseBoolean( value ) ) {
|
|
||||||
RelayReceiver.RestartTimer( context, true );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void init( Application app )
|
public static void init( Application app )
|
||||||
|
|
|
@ -24,12 +24,16 @@ import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.text.Html;
|
||||||
|
import android.text.TextUtils;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.concurrent.locks.Lock;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import android.text.Html;
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import junit.framework.Assert;
|
import junit.framework.Assert;
|
||||||
|
|
||||||
|
@ -311,6 +315,7 @@ public class GameUtils {
|
||||||
GameLock lock = new GameLock( rowid, true );
|
GameLock lock = new GameLock( rowid, true );
|
||||||
if ( lock.tryLock() ) {
|
if ( lock.tryLock() ) {
|
||||||
tellDied( context, lock, informNow );
|
tellDied( context, lock, informNow );
|
||||||
|
Utils.cancelNotification( context, (int)rowid );
|
||||||
DBUtils.deleteGame( context, lock );
|
DBUtils.deleteGame( context, lock );
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
success = true;
|
success = true;
|
||||||
|
@ -361,7 +366,8 @@ public class GameUtils {
|
||||||
String[] dictNames = gi.dictNames();
|
String[] dictNames = gi.dictNames();
|
||||||
DictUtils.DictPairs pairs = DictUtils.openDicts( context, dictNames );
|
DictUtils.DictPairs pairs = DictUtils.openDicts( context, dictNames );
|
||||||
if ( pairs.anyMissing( dictNames ) ) {
|
if ( pairs.anyMissing( dictNames ) ) {
|
||||||
DbgUtils.logf( "loadMakeGame() failing: dict unavailable" );
|
DbgUtils.logf( "loadMakeGame() failing: dicts %s unavailable",
|
||||||
|
TextUtils.join( ",", dictNames ) );
|
||||||
} else {
|
} else {
|
||||||
gamePtr = XwJNI.initJNI();
|
gamePtr = XwJNI.initJNI();
|
||||||
|
|
||||||
|
@ -555,11 +561,26 @@ public class GameUtils {
|
||||||
Intent intent = new Intent();
|
Intent intent = new Intent();
|
||||||
if ( choseEmail ) {
|
if ( choseEmail ) {
|
||||||
intent.setAction( Intent.ACTION_SEND );
|
intent.setAction( Intent.ACTION_SEND );
|
||||||
intent.setType( "message/rfc822");
|
|
||||||
String subject =
|
String subject =
|
||||||
Utils.format( context, R.string.invite_subjectf, room );
|
Utils.format( context, R.string.invite_subjectf, room );
|
||||||
intent.putExtra( Intent.EXTRA_SUBJECT, subject );
|
intent.putExtra( Intent.EXTRA_SUBJECT, subject );
|
||||||
intent.putExtra( Intent.EXTRA_TEXT, Html.fromHtml(message) );
|
intent.putExtra( Intent.EXTRA_TEXT, Html.fromHtml(message) );
|
||||||
|
|
||||||
|
File tmpdir = XWApp.ATTACH_SUPPORTED ?
|
||||||
|
DictUtils.getDownloadDir( context ) : null;
|
||||||
|
if ( null == tmpdir ) { // no attachment
|
||||||
|
intent.setType( "message/rfc822");
|
||||||
|
} else {
|
||||||
|
intent.setType( context.getString( R.string.invite_mime ) );
|
||||||
|
|
||||||
|
File attach = makeJsonFor( tmpdir, room, inviteID, lang,
|
||||||
|
dict, nPlayers );
|
||||||
|
Uri uri = Uri.fromFile( attach );
|
||||||
|
DbgUtils.logf( "using file uri for attachment: %s",
|
||||||
|
uri.toString() );
|
||||||
|
intent.putExtra( Intent.EXTRA_STREAM, uri );
|
||||||
|
}
|
||||||
|
|
||||||
choiceID = R.string.invite_chooser_email;
|
choiceID = R.string.invite_chooser_email;
|
||||||
} else {
|
} else {
|
||||||
intent.setAction( Intent.ACTION_VIEW );
|
intent.setAction( Intent.ACTION_VIEW );
|
||||||
|
@ -724,26 +745,27 @@ public class GameUtils {
|
||||||
CurGameInfo gi = new CurGameInfo( context );
|
CurGameInfo gi = new CurGameInfo( context );
|
||||||
FeedUtilsImpl feedImpl = new FeedUtilsImpl( context, rowid );
|
FeedUtilsImpl feedImpl = new FeedUtilsImpl( context, rowid );
|
||||||
int gamePtr = loadMakeGame( context, gi, feedImpl, sink, lock );
|
int gamePtr = loadMakeGame( context, gi, feedImpl, sink, lock );
|
||||||
|
if ( 0 != gamePtr ) {
|
||||||
XwJNI.comms_resendAll( gamePtr, false, false );
|
XwJNI.comms_resendAll( gamePtr, false, false );
|
||||||
|
|
||||||
if ( null != msgs ) {
|
if ( null != msgs ) {
|
||||||
for ( byte[] msg : msgs ) {
|
for ( byte[] msg : msgs ) {
|
||||||
draw = XwJNI.game_receiveMessage( gamePtr, msg, ret )
|
draw = XwJNI.game_receiveMessage( gamePtr, msg, ret )
|
||||||
|| draw;
|
|| draw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
XwJNI.comms_ackAny( gamePtr );
|
||||||
XwJNI.comms_ackAny( gamePtr );
|
|
||||||
|
|
||||||
// update gi to reflect changes due to messages
|
// update gi to reflect changes due to messages
|
||||||
XwJNI.game_getGi( gamePtr, gi );
|
XwJNI.game_getGi( gamePtr, gi );
|
||||||
saveGame( context, gamePtr, gi, lock, false );
|
saveGame( context, gamePtr, gi, lock, false );
|
||||||
summarizeAndClose( context, lock, gamePtr, gi, feedImpl );
|
summarizeAndClose( context, lock, gamePtr, gi, feedImpl );
|
||||||
|
|
||||||
int flags = setFromFeedImpl( feedImpl );
|
int flags = setFromFeedImpl( feedImpl );
|
||||||
if ( GameSummary.MSG_FLAGS_NONE != flags ) {
|
if ( GameSummary.MSG_FLAGS_NONE != flags ) {
|
||||||
draw = true;
|
draw = true;
|
||||||
DBUtils.setMsgFlags( rowid, flags );
|
DBUtils.setMsgFlags( rowid, flags );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
}
|
}
|
||||||
|
@ -916,5 +938,31 @@ public class GameUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static File makeJsonFor( File dir, String room, String inviteID,
|
||||||
|
int lang, String dict, int nPlayers )
|
||||||
|
{
|
||||||
|
File result = null;
|
||||||
|
if ( XWApp.ATTACH_SUPPORTED ) {
|
||||||
|
JSONObject json = new JSONObject();
|
||||||
|
try {
|
||||||
|
json.put( MultiService.ROOM, room );
|
||||||
|
json.put( MultiService.INVITEID, inviteID );
|
||||||
|
json.put( MultiService.LANG, lang );
|
||||||
|
json.put( MultiService.DICT, dict );
|
||||||
|
json.put( MultiService.NPLAYERST, nPlayers );
|
||||||
|
byte[] data = json.toString().getBytes();
|
||||||
|
|
||||||
|
File file = new File( dir,
|
||||||
|
String.format("invite_%s.json", room ) );
|
||||||
|
FileOutputStream fos = new FileOutputStream( file );
|
||||||
|
fos.write( data, 0, data.length );
|
||||||
|
fos.close();
|
||||||
|
result = file;
|
||||||
|
} catch ( Exception ex ) {
|
||||||
|
DbgUtils.loge( ex );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,17 +46,18 @@ import android.widget.ExpandableListView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
// import android.telephony.PhoneStateListener;
|
// import android.telephony.PhoneStateListener;
|
||||||
// import android.telephony.TelephonyManager;
|
// import android.telephony.TelephonyManager;
|
||||||
import junit.framework.Assert;
|
import junit.framework.Assert;
|
||||||
|
|
||||||
import org.eehouse.android.xw4.jni.*;
|
import org.eehouse.android.xw4.jni.*;
|
||||||
|
|
||||||
public class GamesList extends XWExpandableListActivity
|
public class GamesList extends XWListActivity
|
||||||
implements DispatchNotify.HandleRelaysIface,
|
implements DBUtils.DBChangeListener,
|
||||||
DBUtils.DBChangeListener,
|
|
||||||
GameListAdapter.LoadItemCB,
|
GameListAdapter.LoadItemCB,
|
||||||
NetUtils.DownloadFinishedListener {
|
DictImportActivity.DownloadFinishedListener {
|
||||||
|
|
||||||
private static final int WARN_NODICT = DlgDelegate.DIALOG_LAST + 1;
|
private static final int WARN_NODICT = DlgDelegate.DIALOG_LAST + 1;
|
||||||
private static final int WARN_NODICT_SUBST = WARN_NODICT + 1;
|
private static final int WARN_NODICT_SUBST = WARN_NODICT + 1;
|
||||||
|
@ -66,11 +67,15 @@ public class GamesList extends XWExpandableListActivity
|
||||||
private static final int NEW_GROUP = WARN_NODICT + 5;
|
private static final int NEW_GROUP = WARN_NODICT + 5;
|
||||||
private static final int RENAME_GROUP = WARN_NODICT + 6;
|
private static final int RENAME_GROUP = WARN_NODICT + 6;
|
||||||
private static final int CHANGE_GROUP = WARN_NODICT + 7;
|
private static final int CHANGE_GROUP = WARN_NODICT + 7;
|
||||||
|
private static final int WARN_NODICT_NEW = WARN_NODICT + 8;
|
||||||
|
|
||||||
private static final String SAVE_ROWID = "SAVE_ROWID";
|
private static final String SAVE_ROWID = "SAVE_ROWID";
|
||||||
private static final String SAVE_GROUPID = "SAVE_GROUPID";
|
private static final String SAVE_GROUPID = "SAVE_GROUPID";
|
||||||
private static final String SAVE_DICTNAMES = "SAVE_DICTNAMES";
|
private static final String SAVE_DICTNAMES = "SAVE_DICTNAMES";
|
||||||
|
|
||||||
|
private static final String RELAYIDS_EXTRA = "relayids";
|
||||||
|
private static final String GAMEID_EXTRA = "gameid";
|
||||||
|
|
||||||
private static final int NEW_NET_GAME_ACTION = 1;
|
private static final int NEW_NET_GAME_ACTION = 1;
|
||||||
private static final int RESET_GAME_ACTION = 2;
|
private static final int RESET_GAME_ACTION = 2;
|
||||||
private static final int DELETE_GAME_ACTION = 3;
|
private static final int DELETE_GAME_ACTION = 3;
|
||||||
|
@ -89,7 +94,7 @@ public class GamesList extends XWExpandableListActivity
|
||||||
private GameListAdapter m_adapter;
|
private GameListAdapter m_adapter;
|
||||||
private String m_missingDict;
|
private String m_missingDict;
|
||||||
private String m_missingDictName;
|
private String m_missingDictName;
|
||||||
private long m_missingDictRowId;
|
private long m_missingDictRowId = DBUtils.ROWID_NOTFOUND;
|
||||||
private String[] m_sameLangDicts;
|
private String[] m_sameLangDicts;
|
||||||
private int m_missingDictLang;
|
private int m_missingDictLang;
|
||||||
private long m_rowid;
|
private long m_rowid;
|
||||||
|
@ -111,18 +116,20 @@ public class GamesList extends XWExpandableListActivity
|
||||||
AlertDialog.Builder ab;
|
AlertDialog.Builder ab;
|
||||||
switch ( id ) {
|
switch ( id ) {
|
||||||
case WARN_NODICT:
|
case WARN_NODICT:
|
||||||
|
case WARN_NODICT_NEW:
|
||||||
case WARN_NODICT_SUBST:
|
case WARN_NODICT_SUBST:
|
||||||
lstnr = new DialogInterface.OnClickListener() {
|
lstnr = new DialogInterface.OnClickListener() {
|
||||||
public void onClick( DialogInterface dlg, int item ) {
|
public void onClick( DialogInterface dlg, int item ) {
|
||||||
// just do one
|
// no name, so user must pick
|
||||||
if ( null == m_missingDictName ) {
|
if ( null == m_missingDictName ) {
|
||||||
DictsActivity.launchAndDownload( GamesList.this,
|
DictsActivity.launchAndDownload( GamesList.this,
|
||||||
m_missingDictLang );
|
m_missingDictLang );
|
||||||
} else {
|
} else {
|
||||||
NetUtils.downloadDictInBack( GamesList.this,
|
DictImportActivity
|
||||||
m_missingDictLang,
|
.downloadDictInBack( GamesList.this,
|
||||||
m_missingDictName,
|
m_missingDictLang,
|
||||||
GamesList.this );
|
m_missingDictName,
|
||||||
|
GamesList.this );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -133,6 +140,10 @@ public class GamesList extends XWExpandableListActivity
|
||||||
if ( WARN_NODICT == id ) {
|
if ( WARN_NODICT == id ) {
|
||||||
message = getString( R.string.no_dictf,
|
message = getString( R.string.no_dictf,
|
||||||
gameName, langName );
|
gameName, langName );
|
||||||
|
} else if ( WARN_NODICT_NEW == id ) {
|
||||||
|
message =
|
||||||
|
getString( R.string.invite_dict_missing_body_nonamef,
|
||||||
|
null, m_missingDictName, langName );
|
||||||
} else {
|
} else {
|
||||||
message = getString( R.string.no_dict_substf,
|
message = getString( R.string.no_dict_substf,
|
||||||
gameName, m_missingDictName,
|
gameName, m_missingDictName,
|
||||||
|
@ -142,7 +153,7 @@ public class GamesList extends XWExpandableListActivity
|
||||||
ab = new AlertDialog.Builder( this )
|
ab = new AlertDialog.Builder( this )
|
||||||
.setTitle( R.string.no_dict_title )
|
.setTitle( R.string.no_dict_title )
|
||||||
.setMessage( message )
|
.setMessage( message )
|
||||||
.setPositiveButton( R.string.button_ok, null )
|
.setPositiveButton( R.string.button_cancel, null )
|
||||||
.setNegativeButton( R.string.button_download, lstnr )
|
.setNegativeButton( R.string.button_download, lstnr )
|
||||||
;
|
;
|
||||||
if ( WARN_NODICT_SUBST == id ) {
|
if ( WARN_NODICT_SUBST == id ) {
|
||||||
|
@ -170,8 +181,7 @@ public class GamesList extends XWExpandableListActivity
|
||||||
m_missingDictRowId,
|
m_missingDictRowId,
|
||||||
m_missingDictName,
|
m_missingDictName,
|
||||||
dict );
|
dict );
|
||||||
GameUtils.launchGame( GamesList.this,
|
launchGameIf();
|
||||||
m_missingDictRowId );
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
dialog = new AlertDialog.Builder( this )
|
dialog = new AlertDialog.Builder( this )
|
||||||
|
@ -355,8 +365,7 @@ public class GamesList extends XWExpandableListActivity
|
||||||
{
|
{
|
||||||
super.onNewIntent( intent );
|
super.onNewIntent( intent );
|
||||||
Assert.assertNotNull( intent );
|
Assert.assertNotNull( intent );
|
||||||
invalRelayIDs( intent.
|
invalRelayIDs( intent.getStringArrayExtra( RELAYIDS_EXTRA ) );
|
||||||
getStringArrayExtra( DispatchNotify.RELAYIDS_EXTRA ) );
|
|
||||||
startFirstHasDict( intent );
|
startFirstHasDict( intent );
|
||||||
startNewNetGame( intent );
|
startNewNetGame( intent );
|
||||||
startHasGameID( intent );
|
startHasGameID( intent );
|
||||||
|
@ -366,7 +375,6 @@ public class GamesList extends XWExpandableListActivity
|
||||||
protected void onStart()
|
protected void onStart()
|
||||||
{
|
{
|
||||||
super.onStart();
|
super.onStart();
|
||||||
DispatchNotify.SetRelayIDsHandler( this );
|
|
||||||
|
|
||||||
boolean hide = CommonPrefs.getHideIntro( this );
|
boolean hide = CommonPrefs.getHideIntro( this );
|
||||||
int hereOrGone = hide ? View.GONE : View.VISIBLE;
|
int hereOrGone = hide ? View.GONE : View.VISIBLE;
|
||||||
|
@ -393,7 +401,6 @@ public class GamesList extends XWExpandableListActivity
|
||||||
// (TelephonyManager)getSystemService( Context.TELEPHONY_SERVICE );
|
// (TelephonyManager)getSystemService( Context.TELEPHONY_SERVICE );
|
||||||
// mgr.listen( m_phoneStateListener, PhoneStateListener.LISTEN_NONE );
|
// mgr.listen( m_phoneStateListener, PhoneStateListener.LISTEN_NONE );
|
||||||
// m_phoneStateListener = null;
|
// m_phoneStateListener = null;
|
||||||
DispatchNotify.SetRelayIDsHandler( null );
|
|
||||||
|
|
||||||
super.onStop();
|
super.onStop();
|
||||||
}
|
}
|
||||||
|
@ -436,39 +443,6 @@ public class GamesList extends XWExpandableListActivity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DispatchNotify.HandleRelaysIface interface
|
|
||||||
public void handleRelaysIDs( final String[] relayIDs )
|
|
||||||
{
|
|
||||||
post( new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
invalRelayIDs( relayIDs );
|
|
||||||
startFirstHasDict( relayIDs );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handleInvite( Uri invite )
|
|
||||||
{
|
|
||||||
final NetLaunchInfo nli = new NetLaunchInfo( invite );
|
|
||||||
if ( nli.isValid() ) {
|
|
||||||
post( new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
startNewNetGame( nli );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handleGameID( final int gameID )
|
|
||||||
{
|
|
||||||
post( new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
startHasGameID( gameID );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
// DBUtils.DBChangeListener interface
|
// DBUtils.DBChangeListener interface
|
||||||
public void gameSaved( final long rowid )
|
public void gameSaved( final long rowid )
|
||||||
{
|
{
|
||||||
|
@ -538,8 +512,9 @@ public class GamesList extends XWExpandableListActivity
|
||||||
if ( AlertDialog.BUTTON_POSITIVE == which ) {
|
if ( AlertDialog.BUTTON_POSITIVE == which ) {
|
||||||
switch( id ) {
|
switch( id ) {
|
||||||
case NEW_NET_GAME_ACTION:
|
case NEW_NET_GAME_ACTION:
|
||||||
long rowid = GameUtils.makeNewNetGame( this, m_netLaunchInfo );
|
if ( checkWarnNoDict( m_netLaunchInfo ) ) {
|
||||||
GameUtils.launchGame( this, rowid, true );
|
makeNewNetGameIf();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case RESET_GAME_ACTION:
|
case RESET_GAME_ACTION:
|
||||||
GameUtils.resetGame( this, m_rowid );
|
GameUtils.resetGame( this, m_rowid );
|
||||||
|
@ -724,14 +699,20 @@ public class GamesList extends XWExpandableListActivity
|
||||||
return handled;
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NetUtils.DownloadFinishedListener interface
|
// DictImportActivity.DownloadFinishedListener interface
|
||||||
public void downloadFinished( String name, final boolean success )
|
public void downloadFinished( String name, final boolean success )
|
||||||
{
|
{
|
||||||
post( new Runnable() {
|
post( new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
int id = success ? R.string.download_done
|
boolean madeGame = false;
|
||||||
: R.string.download_failed;
|
if ( success ) {
|
||||||
Utils.showToast( GamesList.this, id );
|
madeGame = makeNewNetGameIf() || launchGameIf();
|
||||||
|
}
|
||||||
|
if ( ! madeGame ) {
|
||||||
|
int id = success ? R.string.download_done
|
||||||
|
: R.string.download_failed;
|
||||||
|
Utils.showToast( GamesList.this, id );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
@ -833,13 +814,38 @@ public class GamesList extends XWExpandableListActivity
|
||||||
return handled;
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean checkWarnNoDict( NetLaunchInfo nli )
|
||||||
|
{
|
||||||
|
// check that we have the dict required
|
||||||
|
boolean haveDict;
|
||||||
|
if ( null == nli.dict ) { // can only test for language support
|
||||||
|
String[] dicts = DictLangCache.getHaveLang( this, nli.lang );
|
||||||
|
haveDict = 0 < dicts.length;
|
||||||
|
if ( haveDict ) {
|
||||||
|
// Just pick one -- good enough for the period when
|
||||||
|
// users aren't using new clients that include the
|
||||||
|
// dict name.
|
||||||
|
nli.dict = dicts[0];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
haveDict =
|
||||||
|
DictLangCache.haveDict( this, nli.lang, nli.dict );
|
||||||
|
}
|
||||||
|
if ( !haveDict ) {
|
||||||
|
m_netLaunchInfo = nli;
|
||||||
|
m_missingDictLang = nli.lang;
|
||||||
|
m_missingDictName = nli.dict;
|
||||||
|
showDialog( WARN_NODICT_NEW );
|
||||||
|
}
|
||||||
|
return haveDict;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean checkWarnNoDict( long rowid )
|
private boolean checkWarnNoDict( long rowid )
|
||||||
{
|
{
|
||||||
String[][] missingNames = new String[1][];
|
String[][] missingNames = new String[1][];
|
||||||
int[] missingLang = new int[1];
|
int[] missingLang = new int[1];
|
||||||
boolean hasDicts = GameUtils.gameDictsHere( this, rowid,
|
boolean hasDicts =
|
||||||
missingNames,
|
GameUtils.gameDictsHere( this, rowid, missingNames, missingLang );
|
||||||
missingLang );
|
|
||||||
if ( !hasDicts ) {
|
if ( !hasDicts ) {
|
||||||
m_missingDictLang = missingLang[0];
|
m_missingDictLang = missingLang[0];
|
||||||
if ( 0 < missingNames[0].length ) {
|
if ( 0 < missingNames[0].length ) {
|
||||||
|
@ -855,7 +861,7 @@ public class GamesList extends XWExpandableListActivity
|
||||||
} else {
|
} else {
|
||||||
String dict = DictLangCache.getHaveLang( this, m_missingDictLang)[0];
|
String dict = DictLangCache.getHaveLang( this, m_missingDictLang)[0];
|
||||||
GameUtils.replaceDicts( this, m_missingDictRowId, null, dict );
|
GameUtils.replaceDicts( this, m_missingDictRowId, null, dict );
|
||||||
GameUtils.launchGame( this, m_missingDictRowId );
|
launchGameIf();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return hasDicts;
|
return hasDicts;
|
||||||
|
@ -899,8 +905,7 @@ public class GamesList extends XWExpandableListActivity
|
||||||
private void startFirstHasDict( Intent intent )
|
private void startFirstHasDict( Intent intent )
|
||||||
{
|
{
|
||||||
if ( null != intent ) {
|
if ( null != intent ) {
|
||||||
String[] relayIDs =
|
String[] relayIDs = intent.getStringArrayExtra( RELAYIDS_EXTRA );
|
||||||
intent.getStringArrayExtra( DispatchNotify.RELAYIDS_EXTRA );
|
|
||||||
startFirstHasDict( relayIDs );
|
startFirstHasDict( relayIDs );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -910,33 +915,35 @@ public class GamesList extends XWExpandableListActivity
|
||||||
startActivity( new Intent( this, NewGameActivity.class ) );
|
startActivity( new Intent( this, NewGameActivity.class ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startNewNetGame( NetLaunchInfo info )
|
private void startNewNetGame( NetLaunchInfo nli )
|
||||||
{
|
{
|
||||||
long rowid = DBUtils.getRowIDForOpen( this, info );
|
Date create = DBUtils.getMostRecentCreate( this, nli );
|
||||||
|
|
||||||
if ( DBUtils.ROWID_NOTFOUND == rowid ) {
|
if ( null == create ) {
|
||||||
rowid = GameUtils.makeNewNetGame( this, info );
|
if ( checkWarnNoDict( nli ) ) {
|
||||||
GameUtils.launchGame( this, rowid, true );
|
makeNewNetGame( nli );
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
String msg = getString( R.string.dup_game_queryf, info.room );
|
String msg = getString( R.string.dup_game_queryf,
|
||||||
m_netLaunchInfo = info;
|
create.toString() );
|
||||||
|
m_netLaunchInfo = nli;
|
||||||
showConfirmThen( msg, NEW_NET_GAME_ACTION );
|
showConfirmThen( msg, NEW_NET_GAME_ACTION );
|
||||||
}
|
}
|
||||||
} // startNewNetGame
|
} // startNewNetGame
|
||||||
|
|
||||||
private void startNewNetGame( Intent intent )
|
private void startNewNetGame( Intent intent )
|
||||||
{
|
{
|
||||||
NetLaunchInfo info = null;
|
NetLaunchInfo nli = null;
|
||||||
if ( MultiService.isMissingDictIntent( intent ) ) {
|
if ( MultiService.isMissingDictIntent( intent ) ) {
|
||||||
info = new NetLaunchInfo( intent );
|
nli = new NetLaunchInfo( intent );
|
||||||
} else {
|
} else {
|
||||||
Uri data = intent.getData();
|
Uri data = intent.getData();
|
||||||
if ( null != data ) {
|
if ( null != data ) {
|
||||||
info = new NetLaunchInfo( data );
|
nli = new NetLaunchInfo( this, data );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( null != info && info.isValid() ) {
|
if ( null != nli && nli.isValid() ) {
|
||||||
startNewNetGame( info );
|
startNewNetGame( nli );
|
||||||
}
|
}
|
||||||
} // startNewNetGame
|
} // startNewNetGame
|
||||||
|
|
||||||
|
@ -950,7 +957,7 @@ public class GamesList extends XWExpandableListActivity
|
||||||
|
|
||||||
private void startHasGameID( Intent intent )
|
private void startHasGameID( Intent intent )
|
||||||
{
|
{
|
||||||
int gameID = intent.getIntExtra( DispatchNotify.GAMEID_EXTRA, 0 );
|
int gameID = intent.getIntExtra( GAMEID_EXTRA, 0 );
|
||||||
if ( 0 != gameID ) {
|
if ( 0 != gameID ) {
|
||||||
startHasGameID( gameID );
|
startHasGameID( gameID );
|
||||||
}
|
}
|
||||||
|
@ -992,9 +999,65 @@ public class GamesList extends XWExpandableListActivity
|
||||||
return dialog;
|
return dialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean makeNewNetGameIf()
|
||||||
|
{
|
||||||
|
boolean madeGame = null != m_netLaunchInfo;
|
||||||
|
if ( madeGame ) {
|
||||||
|
makeNewNetGame( m_netLaunchInfo );
|
||||||
|
m_netLaunchInfo = null;
|
||||||
|
}
|
||||||
|
return madeGame;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean launchGameIf()
|
||||||
|
{
|
||||||
|
boolean madeGame = DBUtils.ROWID_NOTFOUND != m_missingDictRowId;
|
||||||
|
if ( madeGame ) {
|
||||||
|
GameUtils.launchGame( this, m_missingDictRowId );
|
||||||
|
m_missingDictRowId = DBUtils.ROWID_NOTFOUND;
|
||||||
|
}
|
||||||
|
return madeGame;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void makeNewNetGame( NetLaunchInfo info )
|
||||||
|
{
|
||||||
|
long rowid = GameUtils.makeNewNetGame( this, info );
|
||||||
|
GameUtils.launchGame( this, rowid, true );
|
||||||
|
}
|
||||||
|
|
||||||
public static void onGameDictDownload( Context context, Intent intent )
|
public static void onGameDictDownload( Context context, Intent intent )
|
||||||
{
|
{
|
||||||
intent.setClass( context, GamesList.class );
|
intent.setClass( context, GamesList.class );
|
||||||
context.startActivity( intent );
|
context.startActivity( intent );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Intent makeSelfIntent( Context context )
|
||||||
|
{
|
||||||
|
Intent intent = new Intent( context, GamesList.class );
|
||||||
|
intent.setFlags( Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||||
|
| Intent.FLAG_ACTIVITY_NEW_TASK );
|
||||||
|
return intent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Intent makeRelayIdsIntent( Context context,
|
||||||
|
String[] relayIDs )
|
||||||
|
{
|
||||||
|
Intent intent = makeSelfIntent( context );
|
||||||
|
intent.putExtra( RELAYIDS_EXTRA, relayIDs );
|
||||||
|
return intent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Intent makeGameIDIntent( Context context, int gameID )
|
||||||
|
{
|
||||||
|
Intent intent = makeSelfIntent( context );
|
||||||
|
intent.putExtra( GAMEID_EXTRA, gameID );
|
||||||
|
return intent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void openGame( Context context, Uri data )
|
||||||
|
{
|
||||||
|
Intent intent = makeSelfIntent( context );
|
||||||
|
intent.setData( data );
|
||||||
|
context.startActivity( intent );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,12 +20,15 @@
|
||||||
|
|
||||||
package org.eehouse.android.xw4;
|
package org.eehouse.android.xw4;
|
||||||
|
|
||||||
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri.Builder;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import junit.framework.Assert;
|
||||||
|
|
||||||
|
|
||||||
public class NetLaunchInfo {
|
public class NetLaunchInfo {
|
||||||
|
@ -64,18 +67,35 @@ public class NetLaunchInfo {
|
||||||
m_valid = bundle.getBoolean( VALID );
|
m_valid = bundle.getBoolean( VALID );
|
||||||
}
|
}
|
||||||
|
|
||||||
public NetLaunchInfo( Uri data )
|
public NetLaunchInfo( Context context, Uri data )
|
||||||
{
|
{
|
||||||
m_valid = false;
|
m_valid = false;
|
||||||
if ( null != data ) {
|
if ( null != data ) {
|
||||||
|
String scheme = data.getScheme();
|
||||||
try {
|
try {
|
||||||
room = data.getQueryParameter( "room" );
|
if ( "content".equals(scheme) ) {
|
||||||
inviteID = data.getQueryParameter( "id" );
|
Assert.assertNotNull( context );
|
||||||
dict = data.getQueryParameter( "wl" );
|
ContentResolver resolver = context.getContentResolver();
|
||||||
String langStr = data.getQueryParameter( "lang" );
|
InputStream is = resolver.openInputStream( data );
|
||||||
lang = Integer.decode( langStr );
|
int len = is.available();
|
||||||
String np = data.getQueryParameter( "np" );
|
byte[] buf = new byte[len];
|
||||||
nPlayersT = Integer.decode( np );
|
is.read( buf );
|
||||||
|
|
||||||
|
JSONObject json = new JSONObject( new String( buf ) );
|
||||||
|
room = json.getString( MultiService.ROOM );
|
||||||
|
inviteID = json.getString( MultiService.INVITEID );
|
||||||
|
lang = json.getInt( MultiService.LANG );
|
||||||
|
dict = json.getString( MultiService.DICT );
|
||||||
|
nPlayersT = json.getInt( MultiService.NPLAYERST );
|
||||||
|
} else {
|
||||||
|
room = data.getQueryParameter( "room" );
|
||||||
|
inviteID = data.getQueryParameter( "id" );
|
||||||
|
dict = data.getQueryParameter( "wl" );
|
||||||
|
String langStr = data.getQueryParameter( "lang" );
|
||||||
|
lang = Integer.decode( langStr );
|
||||||
|
String np = data.getQueryParameter( "np" );
|
||||||
|
nPlayersT = Integer.decode( np );
|
||||||
|
}
|
||||||
m_valid = true;
|
m_valid = true;
|
||||||
} catch ( Exception e ) {
|
} catch ( Exception e ) {
|
||||||
DbgUtils.logf( "unable to parse \"%s\"", data.toString() );
|
DbgUtils.logf( "unable to parse \"%s\"", data.toString() );
|
||||||
|
@ -99,15 +119,15 @@ public class NetLaunchInfo {
|
||||||
String inviteID, int lang,
|
String inviteID, int lang,
|
||||||
String dict, int nPlayersT )
|
String dict, int nPlayersT )
|
||||||
{
|
{
|
||||||
Builder ub = new Builder();
|
Uri.Builder ub = new Uri.Builder()
|
||||||
ub.scheme( "http" );
|
.scheme( "http" )
|
||||||
ub.path( context.getString( R.string.game_url_pathf,
|
.path( String.format( "//%s%s",
|
||||||
XWPrefs.getDefaultRedirHost( context ) ) );
|
context.getString(R.string.invite_host),
|
||||||
|
context.getString(R.string.invite_prefix) ) )
|
||||||
ub.appendQueryParameter( "lang", String.format("%d", lang ) );
|
.appendQueryParameter( "lang", String.format("%d", lang ) )
|
||||||
ub.appendQueryParameter( "np", String.format( "%d", nPlayersT ) );
|
.appendQueryParameter( "np", String.format( "%d", nPlayersT ) )
|
||||||
ub.appendQueryParameter( "room", room );
|
.appendQueryParameter( "room", room )
|
||||||
ub.appendQueryParameter( "id", inviteID );
|
.appendQueryParameter( "id", inviteID );
|
||||||
if ( null != dict ) {
|
if ( null != dict ) {
|
||||||
ub.appendQueryParameter( "wl", dict );
|
ub.appendQueryParameter( "wl", dict );
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,17 +21,11 @@
|
||||||
package org.eehouse.android.xw4;
|
package org.eehouse.android.xw4;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Handler;
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.URL;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
@ -50,10 +44,6 @@ public class NetUtils {
|
||||||
public static byte PRX_GET_MSGS = 4;
|
public static byte PRX_GET_MSGS = 4;
|
||||||
public static byte PRX_PUT_MSGS = 5;
|
public static byte PRX_PUT_MSGS = 5;
|
||||||
|
|
||||||
public interface DownloadFinishedListener {
|
|
||||||
void downloadFinished( String name, boolean success );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Socket makeProxySocket( Context context,
|
public static Socket makeProxySocket( Context context,
|
||||||
int timeoutMillis )
|
int timeoutMillis )
|
||||||
{
|
{
|
||||||
|
@ -273,68 +263,4 @@ public class NetUtils {
|
||||||
DbgUtils.logf( "sendToRelay: null msgs" );
|
DbgUtils.logf( "sendToRelay: null msgs" );
|
||||||
}
|
}
|
||||||
} // sendToRelay
|
} // sendToRelay
|
||||||
|
|
||||||
static void downloadDictInBack( Context context, int lang, String name,
|
|
||||||
DownloadFinishedListener lstnr )
|
|
||||||
{
|
|
||||||
DictUtils.DictLoc loc = XWPrefs.getDefaultLoc( context );
|
|
||||||
downloadDictInBack( context, lang, name, loc, lstnr );
|
|
||||||
}
|
|
||||||
|
|
||||||
static void downloadDictInBack( Context context, int lang, String name,
|
|
||||||
DictUtils.DictLoc loc,
|
|
||||||
DownloadFinishedListener lstnr )
|
|
||||||
{
|
|
||||||
String url = Utils.makeDictUrl( context, lang, name );
|
|
||||||
downloadDictInBack( context, url, loc, lstnr );
|
|
||||||
}
|
|
||||||
|
|
||||||
static void downloadDictInBack( final Context context, final String urlStr,
|
|
||||||
final DictUtils.DictLoc loc,
|
|
||||||
final DownloadFinishedListener lstnr )
|
|
||||||
{
|
|
||||||
String tmp = Utils.dictFromURL( context, urlStr );
|
|
||||||
final String name = DictUtils.removeDictExtn( tmp );
|
|
||||||
String msg = context.getString( R.string.downloadingf, name );
|
|
||||||
final StatusNotifier sno =
|
|
||||||
new StatusNotifier( context, msg, R.string.download_done );
|
|
||||||
|
|
||||||
new Thread( new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
boolean success = false;
|
|
||||||
HttpURLConnection urlConn = null;
|
|
||||||
try {
|
|
||||||
URL url = new URL( urlStr );
|
|
||||||
urlConn = (HttpURLConnection)url.openConnection();
|
|
||||||
InputStream in = new
|
|
||||||
BufferedInputStream( urlConn.getInputStream(),
|
|
||||||
1024*8 );
|
|
||||||
success = DictUtils.saveDict( context, in,
|
|
||||||
name, loc );
|
|
||||||
|
|
||||||
} catch ( java.net.MalformedURLException mue ) {
|
|
||||||
DbgUtils.loge( mue );
|
|
||||||
} catch ( java.io.IOException ioe ) {
|
|
||||||
DbgUtils.loge( ioe );
|
|
||||||
} catch ( Exception ce ) {
|
|
||||||
// E.g. java.net.ConnectException; we failed
|
|
||||||
// to download, ok.
|
|
||||||
} finally {
|
|
||||||
if ( null != urlConn ) {
|
|
||||||
urlConn.disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sno.close();
|
|
||||||
|
|
||||||
if ( success ) {
|
|
||||||
DictLangCache.inval( context, name, loc, true );
|
|
||||||
}
|
|
||||||
if ( null != lstnr ) {
|
|
||||||
lstnr.downloadFinished( name, success );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} ).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,13 +63,13 @@ public class RelayService extends Service {
|
||||||
long[] rowids = DBUtils.getRowIDsFor( this, relayID );
|
long[] rowids = DBUtils.getRowIDsFor( this, relayID );
|
||||||
if ( null != rowids ) {
|
if ( null != rowids ) {
|
||||||
for ( long rowid : rowids ) {
|
for ( long rowid : rowids ) {
|
||||||
Intent intent = new Intent( this, DispatchNotify.class );
|
Intent intent =
|
||||||
intent.putExtra( DispatchNotify.RELAYIDS_EXTRA,
|
GamesList.makeRelayIdsIntent( this,
|
||||||
new String[] {relayID} );
|
new String[] {relayID} );
|
||||||
String msg = Utils.format( this, R.string.notify_bodyf,
|
String msg = Utils.format( this, R.string.notify_bodyf,
|
||||||
GameUtils.getName( this, rowid ) );
|
GameUtils.getName( this, rowid ) );
|
||||||
Utils.postNotification( this, intent, R.string.notify_title,
|
Utils.postNotification( this, intent, R.string.notify_title,
|
||||||
msg, relayID.hashCode() );
|
msg, (int)rowid );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,9 +112,7 @@ public class RelayService extends Service {
|
||||||
if ( 0 < idsWMsgs.size() ) {
|
if ( 0 < idsWMsgs.size() ) {
|
||||||
String[] relayIDs = new String[idsWMsgs.size()];
|
String[] relayIDs = new String[idsWMsgs.size()];
|
||||||
idsWMsgs.toArray( relayIDs );
|
idsWMsgs.toArray( relayIDs );
|
||||||
// if ( !DispatchNotify.tryHandle( relayIDs ) ) {
|
|
||||||
setupNotification( relayIDs );
|
setupNotification( relayIDs );
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
sink.send( this );
|
sink.send( this );
|
||||||
}
|
}
|
||||||
|
|
|
@ -388,7 +388,6 @@ public class SMSService extends Service {
|
||||||
int count = (msg.length() + (MAX_LEN_TEXT-1)) / MAX_LEN_TEXT;
|
int count = (msg.length() + (MAX_LEN_TEXT-1)) / MAX_LEN_TEXT;
|
||||||
String[] result = new String[count];
|
String[] result = new String[count];
|
||||||
int msgID = ++s_nSent % 0x000000FF;
|
int msgID = ++s_nSent % 0x000000FF;
|
||||||
DbgUtils.logf( "preparing %d packets for msgid %x", count, msgID );
|
|
||||||
|
|
||||||
int start = 0;
|
int start = 0;
|
||||||
int end = 0;
|
int end = 0;
|
||||||
|
@ -400,7 +399,6 @@ public class SMSService extends Service {
|
||||||
end += len;
|
end += len;
|
||||||
result[ii] = String.format( "0:%X:%X:%X:%s", msgID, ii, count,
|
result[ii] = String.format( "0:%X:%X:%X:%s", msgID, ii, count,
|
||||||
msg.substring( start, end ) );
|
msg.substring( start, end ) );
|
||||||
DbgUtils.logf( "fragment[%d]: %s", ii, result[ii] );
|
|
||||||
start = end;
|
start = end;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -432,7 +430,8 @@ public class SMSService extends Service {
|
||||||
MultiService.OWNER_SMS );
|
MultiService.OWNER_SMS );
|
||||||
intent.putExtra( MultiService.INVITER,
|
intent.putExtra( MultiService.INVITER,
|
||||||
Utils.phoneToContact( this, phone, true ) );
|
Utils.phoneToContact( this, phone, true ) );
|
||||||
MultiService.postMissingDictNotification( this, intent, gameID );
|
MultiService.postMissingDictNotification( this, intent,
|
||||||
|
gameID );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DATA:
|
case DATA:
|
||||||
|
@ -504,7 +503,6 @@ public class SMSService extends Service {
|
||||||
|
|
||||||
private void disAssemble( String senderPhone, String fullMsg )
|
private void disAssemble( String senderPhone, String fullMsg )
|
||||||
{
|
{
|
||||||
DbgUtils.logf( "disAssemble()" );
|
|
||||||
byte[] data = XwJNI.base64Decode( fullMsg );
|
byte[] data = XwJNI.base64Decode( fullMsg );
|
||||||
DataInputStream dis =
|
DataInputStream dis =
|
||||||
new DataInputStream( new ByteArrayInputStream(data) );
|
new DataInputStream( new ByteArrayInputStream(data) );
|
||||||
|
@ -542,7 +540,7 @@ public class SMSService extends Service {
|
||||||
String owner = Utils.phoneToContact( this, phone, true );
|
String owner = Utils.phoneToContact( this, phone, true );
|
||||||
String body = Utils.format( this, R.string.new_name_bodyf,
|
String body = Utils.format( this, R.string.new_name_bodyf,
|
||||||
owner );
|
owner );
|
||||||
postNotification( gameID, R.string.new_sms_title, body );
|
postNotification( gameID, R.string.new_sms_title, body, rowid );
|
||||||
|
|
||||||
ackInvite( phone, gameID );
|
ackInvite( phone, gameID );
|
||||||
}
|
}
|
||||||
|
@ -563,8 +561,6 @@ public class SMSService extends Service {
|
||||||
for ( String fragment : fragments ) {
|
for ( String fragment : fragments ) {
|
||||||
String asPublic = toPublicFmt( fragment );
|
String asPublic = toPublicFmt( fragment );
|
||||||
mgr.sendTextMessage( phone, null, asPublic, sent, delivery );
|
mgr.sendTextMessage( phone, null, asPublic, sent, delivery );
|
||||||
DbgUtils.logf( "Message \"%s\" of %d bytes sent to %s.",
|
|
||||||
asPublic, asPublic.length(), phone );
|
|
||||||
}
|
}
|
||||||
if ( s_showToasts ) {
|
if ( s_showToasts ) {
|
||||||
DbgUtils.showf( this, "sent %dth msg", s_nSent );
|
DbgUtils.showf( this, "sent %dth msg", s_nSent );
|
||||||
|
@ -607,19 +603,19 @@ public class SMSService extends Service {
|
||||||
if ( GameUtils.feedMessage( this, rowid, msg, addr,
|
if ( GameUtils.feedMessage( this, rowid, msg, addr,
|
||||||
sink ) ) {
|
sink ) ) {
|
||||||
postNotification( gameID, R.string.new_smsmove_title,
|
postNotification( gameID, R.string.new_smsmove_title,
|
||||||
getString(R.string.new_move_body)
|
getString(R.string.new_move_body),
|
||||||
);
|
rowid );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void postNotification( int gameID, int title, String body )
|
private void postNotification( int gameID, int title, String body,
|
||||||
|
long rowid )
|
||||||
{
|
{
|
||||||
Intent intent = new Intent( this, DispatchNotify.class );
|
Intent intent = GamesList.makeGameIDIntent( this, gameID );
|
||||||
intent.putExtra( DispatchNotify.GAMEID_EXTRA, gameID );
|
Utils.postNotification( this, intent, title, body, (int)rowid );
|
||||||
Utils.postNotification( this, intent, title, body, gameID );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Runs in separate thread
|
// Runs in separate thread
|
||||||
|
@ -664,11 +660,9 @@ public class SMSService extends Service {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context arg0, Intent arg1)
|
public void onReceive(Context arg0, Intent arg1)
|
||||||
{
|
{
|
||||||
DbgUtils.logf( "got MSG_DELIVERED" );
|
|
||||||
switch ( getResultCode() ) {
|
switch ( getResultCode() ) {
|
||||||
case Activity.RESULT_OK:
|
case Activity.RESULT_OK:
|
||||||
sendResult( MultiEvent.SMS_SEND_OK );
|
sendResult( MultiEvent.SMS_SEND_OK );
|
||||||
DbgUtils.logf( "SUCCESS!!!" );
|
|
||||||
break;
|
break;
|
||||||
case SmsManager.RESULT_ERROR_RADIO_OFF:
|
case SmsManager.RESULT_ERROR_RADIO_OFF:
|
||||||
DbgUtils.showf( SMSService.this, "NO RADIO!!!" );
|
DbgUtils.showf( SMSService.this, "NO RADIO!!!" );
|
||||||
|
@ -688,7 +682,6 @@ public class SMSService extends Service {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context arg0, Intent arg1)
|
public void onReceive(Context arg0, Intent arg1)
|
||||||
{
|
{
|
||||||
DbgUtils.logf( "got MSG_DELIVERED" );
|
|
||||||
if ( Activity.RESULT_OK == getResultCode() ) {
|
if ( Activity.RESULT_OK == getResultCode() ) {
|
||||||
DbgUtils.logf( "SUCCESS!!!" );
|
DbgUtils.logf( "SUCCESS!!!" );
|
||||||
} else {
|
} else {
|
||||||
|
@ -709,7 +702,6 @@ public class SMSService extends Service {
|
||||||
public int transportSend( byte[] buf, final CommsAddrRec addr, int gameID )
|
public int transportSend( byte[] buf, final CommsAddrRec addr, int gameID )
|
||||||
{
|
{
|
||||||
int nSent = -1;
|
int nSent = -1;
|
||||||
DbgUtils.logf( "SMSMsgSink.transportSend()" );
|
|
||||||
if ( null != addr ) {
|
if ( null != addr ) {
|
||||||
nSent = sendPacket( addr.sms_phone, gameID, buf );
|
nSent = sendPacket( addr.sms_phone, gameID, buf );
|
||||||
} else {
|
} else {
|
||||||
|
@ -752,7 +744,6 @@ public class SMSService extends Service {
|
||||||
public boolean isComplete()
|
public boolean isComplete()
|
||||||
{
|
{
|
||||||
boolean complete = m_msgs.length == m_haveCount;
|
boolean complete = m_msgs.length == m_haveCount;
|
||||||
DbgUtils.logf( "isComplete(msg %d)=>%b", m_msgID, complete );
|
|
||||||
return complete;
|
return complete;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
|
|
||||||
/*
|
|
||||||
* Copyright 2012 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.eehouse.android.xw4;
|
|
||||||
|
|
||||||
import android.app.Notification;
|
|
||||||
import android.app.NotificationManager;
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
|
|
||||||
public class StatusNotifier {
|
|
||||||
private int m_id;
|
|
||||||
private NotificationManager m_mgr;
|
|
||||||
private Context m_context;
|
|
||||||
|
|
||||||
public StatusNotifier( Context context, String msg, int id )
|
|
||||||
{
|
|
||||||
m_context = context;
|
|
||||||
m_id = id;
|
|
||||||
|
|
||||||
Notification notification =
|
|
||||||
new Notification( R.drawable.icon48x48, msg,
|
|
||||||
System.currentTimeMillis() );
|
|
||||||
notification.flags = notification.flags |= Notification.FLAG_AUTO_CANCEL;
|
|
||||||
PendingIntent pi = PendingIntent.getActivity( context, 0,
|
|
||||||
new Intent(), 0 );
|
|
||||||
notification.setLatestEventInfo( context, "", "", pi );
|
|
||||||
|
|
||||||
m_mgr = (NotificationManager)
|
|
||||||
context.getSystemService( Context.NOTIFICATION_SERVICE );
|
|
||||||
m_mgr.notify( id, notification );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Will likely be called from background thread
|
|
||||||
public void close()
|
|
||||||
{
|
|
||||||
m_mgr.cancel( m_id );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -197,9 +197,8 @@ public class UpdateCheckReceiver extends BroadcastReceiver {
|
||||||
intent = new Intent( Intent.ACTION_VIEW,
|
intent = new Intent( Intent.ACTION_VIEW,
|
||||||
Uri.parse(url) );
|
Uri.parse(url) );
|
||||||
} else {
|
} else {
|
||||||
intent = new Intent( context,
|
intent = DictImportActivity
|
||||||
DictImportActivity.class );
|
.makeAppDownloadIntent( context, url );
|
||||||
intent.putExtra( DictImportActivity.APK_EXTRA, url );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String title =
|
String title =
|
||||||
|
|
|
@ -174,7 +174,8 @@ public class Utils {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void postNotification( Context context, Intent intent,
|
public static void postNotification( Context context, Intent intent,
|
||||||
String title, String body, int id )
|
String title, String body,
|
||||||
|
int id )
|
||||||
{
|
{
|
||||||
/* s_nextCode: per this link
|
/* s_nextCode: per this link
|
||||||
http://stackoverflow.com/questions/10561419/scheduling-more-than-one-pendingintent-to-same-activity-using-alarmmanager
|
http://stackoverflow.com/questions/10561419/scheduling-more-than-one-pendingintent-to-same-activity-using-alarmmanager
|
||||||
|
@ -425,7 +426,8 @@ public class Utils {
|
||||||
|
|
||||||
public static Intent makeInstallIntent( File file )
|
public static Intent makeInstallIntent( File file )
|
||||||
{
|
{
|
||||||
Uri uri = Uri.parse( "file:/" + file.getPath() );
|
String withScheme = "file://" + file.getPath();
|
||||||
|
Uri uri = Uri.parse( withScheme );
|
||||||
Intent intent = new Intent( Intent.ACTION_VIEW );
|
Intent intent = new Intent( Intent.ACTION_VIEW );
|
||||||
intent.setDataAndType( uri, XWConstants.APK_TYPE );
|
intent.setDataAndType( uri, XWConstants.APK_TYPE );
|
||||||
intent.addFlags( Intent.FLAG_ACTIVITY_NEW_TASK );
|
intent.addFlags( Intent.FLAG_ACTIVITY_NEW_TASK );
|
||||||
|
@ -442,7 +444,6 @@ public class Utils {
|
||||||
pm.queryIntentActivities( intent,
|
pm.queryIntentActivities( intent,
|
||||||
PackageManager.MATCH_DEFAULT_ONLY );
|
PackageManager.MATCH_DEFAULT_ONLY );
|
||||||
result = 0 < doers.size();
|
result = 0 < doers.size();
|
||||||
DbgUtils.logf( "canInstall()=>%b", result );
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,6 @@ public class XWActivity extends Activity
|
||||||
{
|
{
|
||||||
DbgUtils.logf( "%s.onStart(this=%H)", getClass().getName(), this );
|
DbgUtils.logf( "%s.onStart(this=%H)", getClass().getName(), this );
|
||||||
super.onStart();
|
super.onStart();
|
||||||
DispatchNotify.SetRunning( this );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -73,7 +72,6 @@ public class XWActivity extends Activity
|
||||||
protected void onStop()
|
protected void onStop()
|
||||||
{
|
{
|
||||||
DbgUtils.logf( "%s.onStop(this=%H)", getClass().getName(), this );
|
DbgUtils.logf( "%s.onStop(this=%H)", getClass().getName(), this );
|
||||||
DispatchNotify.ClearRunning( this );
|
|
||||||
super.onStop();
|
super.onStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ public class XWApp extends Application {
|
||||||
public static final boolean BTSUPPORTED = false;
|
public static final boolean BTSUPPORTED = false;
|
||||||
public static final boolean SMSSUPPORTED = true;
|
public static final boolean SMSSUPPORTED = true;
|
||||||
public static final boolean GCMSUPPORTED = true;
|
public static final boolean GCMSUPPORTED = true;
|
||||||
|
public static final boolean ATTACH_SUPPORTED = false;
|
||||||
public static final boolean DEBUG = true;
|
public static final boolean DEBUG = true;
|
||||||
|
|
||||||
public static final String SMS_PUBLIC_HEADER = "-XW4";
|
public static final String SMS_PUBLIC_HEADER = "-XW4";
|
||||||
|
|
|
@ -45,7 +45,6 @@ public class XWListActivity extends ListActivity
|
||||||
{
|
{
|
||||||
DbgUtils.logf( "%s.onStart(this=%H)", getClass().getName(), this );
|
DbgUtils.logf( "%s.onStart(this=%H)", getClass().getName(), this );
|
||||||
super.onStart();
|
super.onStart();
|
||||||
DispatchNotify.SetRunning( this );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -70,7 +69,6 @@ public class XWListActivity extends ListActivity
|
||||||
protected void onStop()
|
protected void onStop()
|
||||||
{
|
{
|
||||||
DbgUtils.logf( "%s.onStop(this=%H)", getClass().getName(), this );
|
DbgUtils.logf( "%s.onStop(this=%H)", getClass().getName(), this );
|
||||||
DispatchNotify.ClearRunning( this );
|
|
||||||
super.onStop();
|
super.onStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,11 +45,6 @@ public class XWPrefs {
|
||||||
return getPrefsString( context, R.string.key_relay_host );
|
return getPrefsString( context, R.string.key_relay_host );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getDefaultRedirHost( Context context )
|
|
||||||
{
|
|
||||||
return getPrefsString( context, R.string.key_redir_host );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getDefaultRelayPort( Context context )
|
public static int getDefaultRelayPort( Context context )
|
||||||
{
|
{
|
||||||
String val = getPrefsString( context, R.string.key_relay_port );
|
String val = getPrefsString( context, R.string.key_relay_port );
|
||||||
|
|
106
xwords4/android/scripts/and_index.php
Normal file
106
xwords4/android/scripts/and_index.php
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$g_androidStrings = array( "android", );
|
||||||
|
$g_apk = 'XWords4-release_android_beta_55-39-gbffb231.apk';
|
||||||
|
|
||||||
|
function printHead() {
|
||||||
|
print <<<EOF
|
||||||
|
|
||||||
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/xw4mobile.css" />
|
||||||
|
<title>Crosswords Invite redirect</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="center">
|
||||||
|
<img class="center" src="../icon48x48.png"/>
|
||||||
|
</div>
|
||||||
|
EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
function printTail() {
|
||||||
|
print <<<EOF
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
function printNonAndroid($agent) {
|
||||||
|
$subject = "Android device not identified";
|
||||||
|
|
||||||
|
$body = htmlentities("My browser is running on an android device but"
|
||||||
|
. " says its user agent is: \"$agent\". Please fix your script to recognize"
|
||||||
|
. " this as an Android browser.");
|
||||||
|
print <<<EOF
|
||||||
|
<div class="center">
|
||||||
|
<p>This page is meant to be viewed on an Android device.</p>
|
||||||
|
<hr>
|
||||||
|
<p>(If you <em>are</em> viewing this on an Android device, you've
|
||||||
|
found a bug! Please <a href="mailto:
|
||||||
|
xwords@eehouse.org?subject=$subject&body=$body">email me</a> (and be
|
||||||
|
sure to leave the user agent string in the email body.)
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
function printAndroid() {
|
||||||
|
print <<<EOF
|
||||||
|
<div>
|
||||||
|
<p>You'll have come here after clicking a link in an email or
|
||||||
|
text inviting you to a Crosswords game. But you should not be seeing
|
||||||
|
this page.</p>
|
||||||
|
|
||||||
|
<p>If you got this page on your device, it means either
|
||||||
|
<ul>
|
||||||
|
<li>The copy of Crosswords you have is NOT beta 56 or newer (dating from about Dec. 1, 2012).</li>
|
||||||
|
<li> OR </li>
|
||||||
|
<li> that your copy of Crosswords is new enough <em>BUT</em> that
|
||||||
|
when you clicked on the link and were asked to choose between a
|
||||||
|
browser and Crosswords you chose the browser.</li>
|
||||||
|
</ul></p>
|
||||||
|
|
||||||
|
<p>In the first case, install the latest Crosswords,
|
||||||
|
either <a href="market://search?q=pname:org.eehouse.android.xw4">via
|
||||||
|
the Google Play store</a> or
|
||||||
|
(sideloading) <a href="https://sourceforge.net/projects/xwords/files/xwords_Android/4.4%20beta%2056/XWords4-release_android_beta_56.apk/download">via
|
||||||
|
Sourceforge.net</a>. After the install is finished go back to the
|
||||||
|
invite email (or text) and tap the link again.</p>
|
||||||
|
|
||||||
|
<p>In the second case, hit your browser's back button, click the
|
||||||
|
link in your invite email (or text) again, and this time let
|
||||||
|
Crosswords handle it.</p>
|
||||||
|
|
||||||
|
<p>Have fun. And as always, <a href="mailto:xwords@eehouse.org">let
|
||||||
|
me know</a> if you have problems or suggestions.</p>
|
||||||
|
</div>
|
||||||
|
<div class="center">
|
||||||
|
<img class="center" src="../icon48x48.png"/>
|
||||||
|
</div>
|
||||||
|
EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Main()
|
||||||
|
**********************************************************************/
|
||||||
|
$agent = $_SERVER['HTTP_USER_AGENT'];
|
||||||
|
$onAndroid = false;
|
||||||
|
for ( $ii = 0; $ii < count($g_androidStrings) && !$onAndroid; ++$ii ) {
|
||||||
|
$needle = $g_androidStrings[$ii];
|
||||||
|
$onAndroid = false !== stripos( $agent, $needle );
|
||||||
|
}
|
||||||
|
$onFire = false !== stripos( $agent, 'silk' );
|
||||||
|
|
||||||
|
printHead();
|
||||||
|
if ( /*true || */ $onFire || $onAndroid ) {
|
||||||
|
printAndroid();
|
||||||
|
} else {
|
||||||
|
printNonAndroid($agent);
|
||||||
|
}
|
||||||
|
printTail();
|
||||||
|
|
||||||
|
|
||||||
|
?>
|
|
@ -1,2 +1,3 @@
|
||||||
body { font-size: 2em; }
|
body { font-size: 1.5em; }
|
||||||
table { font-size: 2em; }
|
table { font-size: 1.5em; }
|
||||||
|
.center { text-align: center; }
|
||||||
|
|
|
@ -45,7 +45,7 @@ CPPFLAGS += -DSPAWN_SELF -g -Wall \
|
||||||
-I $(shell pg_config --includedir) \
|
-I $(shell pg_config --includedir) \
|
||||||
-DSVN_REV=\"$(shell cat $(GITINFO) 2>/dev/null || echo -n $(HASH) )\"
|
-DSVN_REV=\"$(shell cat $(GITINFO) 2>/dev/null || echo -n $(HASH) )\"
|
||||||
# CPPFLAGS += -DDO_HTTP
|
# CPPFLAGS += -DDO_HTTP
|
||||||
# CPPFLAGS += -DHAVE_SENDTIME
|
# CPPFLAGS += -DHAVE_STIME
|
||||||
|
|
||||||
# turn on semaphore debugging
|
# turn on semaphore debugging
|
||||||
# CPPFLAGS += -DDEBUG_LOCKS
|
# CPPFLAGS += -DDEBUG_LOCKS
|
||||||
|
|
|
@ -581,8 +581,8 @@ DBMgr::PendingMsgCount( const char* connName, int hid )
|
||||||
int count = 0;
|
int count = 0;
|
||||||
const char* fmt = "SELECT COUNT(*) FROM " MSGS_TABLE
|
const char* fmt = "SELECT COUNT(*) FROM " MSGS_TABLE
|
||||||
" WHERE connName = '%s' AND hid = %d "
|
" WHERE connName = '%s' AND hid = %d "
|
||||||
#ifdef HAVE_SENDTIME
|
#ifdef HAVE_STIME
|
||||||
"AND sendtime IS NULL"
|
"AND stime IS NULL"
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
string query;
|
string query;
|
||||||
|
@ -692,8 +692,8 @@ DBMgr::CountStoredMessages( const char* const connName, int hid )
|
||||||
{
|
{
|
||||||
const char* fmt = "SELECT count(*) FROM " MSGS_TABLE
|
const char* fmt = "SELECT count(*) FROM " MSGS_TABLE
|
||||||
" WHERE connname = '%s' "
|
" WHERE connname = '%s' "
|
||||||
#ifdef HAVE_SENDTIME
|
#ifdef HAVE_STIME
|
||||||
"AND sendtime IS NULL"
|
"AND stime IS NULL"
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -748,8 +748,8 @@ DBMgr::GetNthStoredMessage( const char* const connName, int hid,
|
||||||
{
|
{
|
||||||
const char* fmt = "SELECT id, msg, msglen FROM " MSGS_TABLE
|
const char* fmt = "SELECT id, msg, msglen FROM " MSGS_TABLE
|
||||||
" WHERE connName = '%s' AND hid = %d "
|
" WHERE connName = '%s' AND hid = %d "
|
||||||
#ifdef HAVE_SENDTIME
|
#ifdef HAVE_STIME
|
||||||
"AND sendtime IS NULL "
|
"AND stime IS NULL "
|
||||||
#endif
|
#endif
|
||||||
"ORDER BY id LIMIT 1 OFFSET %d";
|
"ORDER BY id LIMIT 1 OFFSET %d";
|
||||||
string query;
|
string query;
|
||||||
|
@ -807,8 +807,8 @@ DBMgr::RemoveStoredMessages( const int* msgIDs, int nMsgIDs )
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* fmt =
|
const char* fmt =
|
||||||
#ifdef HAVE_SENDTIME
|
#ifdef HAVE_STIME
|
||||||
"UPDATE " MSGS_TABLE " SET sendtime='now' "
|
"UPDATE " MSGS_TABLE " SET stime='now' "
|
||||||
#else
|
#else
|
||||||
"DELETE FROM " MSGS_TABLE
|
"DELETE FROM " MSGS_TABLE
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -50,10 +50,12 @@ def init():
|
||||||
|
|
||||||
return con
|
return con
|
||||||
|
|
||||||
|
# WHERE stime IS NULL
|
||||||
|
|
||||||
def getPendingMsgs( con, typ ):
|
def getPendingMsgs( con, typ ):
|
||||||
cur = con.cursor()
|
cur = con.cursor()
|
||||||
query = """SELECT id, devid FROM msgs WHERE
|
query = """SELECT id, devid FROM msgs
|
||||||
devid IN (SELECT id FROM devices WHERE devtype=%d)
|
WHERE devid IN (SELECT id FROM devices WHERE devtype=%d)
|
||||||
AND NOT connname IN (SELECT connname FROM games WHERE dead); """
|
AND NOT connname IN (SELECT connname FROM games WHERE dead); """
|
||||||
cur.execute(query % typ)
|
cur.execute(query % typ)
|
||||||
result = cur.fetchall()
|
result = cur.fetchall()
|
||||||
|
@ -75,23 +77,28 @@ def notifyGCM( devids, typ ):
|
||||||
# 'msg' : "I am your father, Luke.",
|
# 'msg' : "I am your father, Luke.",
|
||||||
}
|
}
|
||||||
response = instance.json_request( registration_ids = devids,
|
response = instance.json_request( registration_ids = devids,
|
||||||
data = data )
|
# restricted_package_name = 'org.eehouse.android.xw4',
|
||||||
|
data = data,
|
||||||
|
# collapse_key = 'NewMove',
|
||||||
|
)
|
||||||
if 'errors' in response:
|
if 'errors' in response:
|
||||||
for error, reg_ids in response.items():
|
response = response['errors']
|
||||||
print error
|
if 'NotRegistered' in response:
|
||||||
|
for id in response['NotRegistered']:
|
||||||
|
print 'need to remove "', id, '" from db'
|
||||||
|
else:
|
||||||
|
print "got some kind of error"
|
||||||
else:
|
else:
|
||||||
print 'no errors',
|
if g_debug: print 'no errors:', response
|
||||||
if g_debug: print ':', response
|
|
||||||
else: print
|
|
||||||
else:
|
else:
|
||||||
print "not sending to", len(devids), "devices because typ ==", typ
|
print "not sending to", len(devids), "devices because typ ==", typ
|
||||||
|
|
||||||
def shouldSend(val):
|
def shouldSend(val):
|
||||||
pow = 1
|
return val == 1
|
||||||
while pow < val:
|
# pow = 1
|
||||||
pow *= 2
|
# while pow < val:
|
||||||
return pow == val
|
# pow *= 3
|
||||||
|
# return pow == val
|
||||||
|
|
||||||
# given a list of msgid, devid lists, figure out which messages should
|
# given a list of msgid, devid lists, figure out which messages should
|
||||||
# be sent/resent now and mark them as sent. Backoff is based on
|
# be sent/resent now and mark them as sent. Backoff is based on
|
||||||
|
@ -99,7 +106,6 @@ def shouldSend(val):
|
||||||
# before, backoff applies.
|
# before, backoff applies.
|
||||||
def targetsAfterBackoff( msgs ):
|
def targetsAfterBackoff( msgs ):
|
||||||
global g_sent
|
global g_sent
|
||||||
print 'sent:', g_sent
|
|
||||||
targets = {}
|
targets = {}
|
||||||
for row in msgs:
|
for row in msgs:
|
||||||
msgid = row[0]
|
msgid = row[0]
|
||||||
|
@ -174,16 +180,16 @@ def main():
|
||||||
if 0 < len(targets):
|
if 0 < len(targets):
|
||||||
if 0 < emptyCount: print ""
|
if 0 < emptyCount: print ""
|
||||||
emptyCount = 0
|
emptyCount = 0
|
||||||
print strftime("%Y-%m-%d %H:%M:%S", gmtime()),
|
print strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
|
||||||
print "devices needing notification:", targets
|
print "devices needing notification:", targets
|
||||||
notifyGCM( asGCMIds( g_con, targets, typ ), typ )
|
notifyGCM( asGCMIds( g_con, targets, typ ), typ )
|
||||||
pruneSent( devids )
|
pruneSent( devids )
|
||||||
else:
|
else:
|
||||||
emptyCount += 1
|
emptyCount += 1
|
||||||
if not g_debug:
|
if (0 == (emptyCount%5)) and not g_debug:
|
||||||
sys.stdout.write('.')
|
sys.stdout.write('.')
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
if 0 == (emptyCount % LINE_LEN): print ""
|
if 0 == (emptyCount % (LINE_LEN*5)): print ""
|
||||||
if 0 == loopInterval: break
|
if 0 == loopInterval: break
|
||||||
time.sleep( loopInterval )
|
time.sleep( loopInterval )
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
|
|
||||||
import sys, gcm, psycopg2
|
import sys, gcm, psycopg2, json
|
||||||
|
|
||||||
# I'm not checking my key in...
|
# I'm not checking my key in...
|
||||||
import mykey
|
import mykey
|
||||||
|
|
||||||
|
def usage():
|
||||||
|
print 'usage:', sys.argv[0], '[--to <name>] msg'
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
def msgViaGCM( devid, msg ):
|
def msgViaGCM( devid, msg ):
|
||||||
instance = gcm.GCM( mykey.myKey )
|
instance = gcm.GCM( mykey.myKey )
|
||||||
|
@ -14,18 +17,30 @@ def msgViaGCM( devid, msg ):
|
||||||
|
|
||||||
response = instance.json_request( registration_ids = [devid],
|
response = instance.json_request( registration_ids = [devid],
|
||||||
data = data )
|
data = data )
|
||||||
|
|
||||||
if 'errors' in response:
|
if 'errors' in response:
|
||||||
for error, reg_ids in response.items():
|
response = response['errors']
|
||||||
print error
|
if 'NotRegistered' in response:
|
||||||
|
ids = response['NotRegistered']
|
||||||
|
for id in ids:
|
||||||
|
print 'need to remove "', id, '" from db'
|
||||||
else:
|
else:
|
||||||
print 'no errors'
|
print 'no errors'
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
to = None
|
||||||
msg = sys.argv[1]
|
msg = sys.argv[1]
|
||||||
print 'got "%s"' % msg
|
if msg == '--to':
|
||||||
msgViaGCM( mykey.myBlaze, msg )
|
to = sys.argv[2]
|
||||||
|
msg = sys.argv[3]
|
||||||
|
elif 2 < len(sys.argv):
|
||||||
|
usage()
|
||||||
|
if not to in mykey.devids.keys():
|
||||||
|
print 'Unknown --to param;', to, 'not in', ','.join(mykey.devids.keys())
|
||||||
|
usage()
|
||||||
|
if not to: usage()
|
||||||
|
devid = mykey.devids[to]
|
||||||
|
print 'sending: "%s" to' % msg, to
|
||||||
|
msgViaGCM( devid, msg )
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -98,6 +98,7 @@ $cols = array( new Column("dead", "D", "capitalize", false ),
|
||||||
new Column("clntVers", "CV", "identity", true ),
|
new Column("clntVers", "CV", "identity", true ),
|
||||||
new Column("nperdevice", "NP", "identity", true ),
|
new Column("nperdevice", "NP", "identity", true ),
|
||||||
new Column("ack", "A", "identity", true ),
|
new Column("ack", "A", "identity", true ),
|
||||||
|
new Column("devids", "DevIDs", "identity", true ),
|
||||||
new Column("nsent", "Sent", "identity", false ),
|
new Column("nsent", "Sent", "identity", false ),
|
||||||
new Column("addrs", "Dev. addr", "ip_to_host", true ),
|
new Column("addrs", "Dev. addr", "ip_to_host", true ),
|
||||||
new Column("ctime", "Created", "print_date", false ),
|
new Column("ctime", "Created", "print_date", false ),
|
||||||
|
|
|
@ -68,6 +68,7 @@ id SERIAL
|
||||||
,connName VARCHAR(64)
|
,connName VARCHAR(64)
|
||||||
,hid INTEGER
|
,hid INTEGER
|
||||||
,ctime TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
,ctime TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
,stime TIMESTAMP DEFAULT NULL
|
||||||
,devid INTEGER
|
,devid INTEGER
|
||||||
,msg BYTEA
|
,msg BYTEA
|
||||||
,msglen INTEGER
|
,msglen INTEGER
|
||||||
|
@ -81,6 +82,7 @@ id INTEGER UNIQUE PRIMARY KEY
|
||||||
,devType INTEGER
|
,devType INTEGER
|
||||||
,devid TEXT
|
,devid TEXT
|
||||||
,ctime TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
,ctime TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
,unreg BOOLEAN DEFAULT FALSE
|
||||||
);
|
);
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue