It appears you're running on a Kindle Fire, whose non-standard (from
+an Android perspective) OS doesn't support the custom schemes on which
+Crosswords invitations depend. If you want to accept this invitation
+you'll need to do it the manual way:
+
+
I'm sorry this is so complicated. I'm trying to find a
+workaround for this limitation in the Kindle Fire's operating system
+but for now this is all I can offer.
+
+
-
+
This page is meant to be viewed on a browser on your Android
- device. Please open the email that sent you here on that device to
- complete the invitation process.
+ device. Please open the email that sent you here on that device and
+ revisit this link to complete the invitation process.
(If you are viewing this on an Android device, you've
From 63b29a2cb25a521eba463783026443724cc88ea2 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Sun, 25 Nov 2012 13:55:02 -0800
Subject: [PATCH 056/146] Revert "add read-only debug prefs giving GCM and
relay device IDs."
This reverts commit 5019d3960b0a641d01e22d1824fd8479017f4e51.
---
xwords4/android/XWords4/res/values/common_rsrc.xml | 2 --
xwords4/android/XWords4/res/xml/xwprefs.xml | 10 ----------
2 files changed, 12 deletions(-)
diff --git a/xwords4/android/XWords4/res/values/common_rsrc.xml b/xwords4/android/XWords4/res/values/common_rsrc.xml
index 4d48992a3..e354646b6 100644
--- a/xwords4/android/XWords4/res/values/common_rsrc.xml
+++ b/xwords4/android/XWords4/res/values/common_rsrc.xml
@@ -121,8 +121,6 @@
%1$s/%2$s
Write DB to SD card
Load DB from SD card
- GCM Device ID
- Relay Device ID
diff --git a/xwords4/android/XWords4/res/xml/xwprefs.xml b/xwords4/android/XWords4/res/xml/xwprefs.xml
index 5d221f820..9a5a3bf3c 100644
--- a/xwords4/android/XWords4/res/xml/xwprefs.xml
+++ b/xwords4/android/XWords4/res/xml/xwprefs.xml
@@ -290,16 +290,6 @@
android:summary="@string/git_rev"
android:enabled="false"
/>
-
-
Date: Mon, 26 Nov 2012 03:08:54 -0800
Subject: [PATCH 057/146] don't crash on malformed invite URL
---
.../eehouse/android/xw4/DispatchNotify.java | 61 ++++++++++---------
1 file changed, 33 insertions(+), 28 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DispatchNotify.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DispatchNotify.java
index 57d674d62..0e0d8f9ef 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DispatchNotify.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DispatchNotify.java
@@ -66,36 +66,41 @@ public class DispatchNotify extends Activity {
}
} else if ( null != data ) { // relay invite redirected URL case
NetLaunchInfo nli = new NetLaunchInfo( data );
- 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;
+ 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 {
- 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;
+ DbgUtils.logf( "DispatchNotify: dropping duplicate invite" );
+ GameSummary summary = DBUtils.getSummary( this, rowid );
+ if ( null != summary ) {
+ gameID = summary.gameID;
+ if ( !tryHandle( gameID ) ) {
+ mustLaunch = true;
+ }
}
}
}
From 302ad04ef989462856cb6e53b7b414c3124ecf09 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Mon, 26 Nov 2012 05:41:42 -0800
Subject: [PATCH 058/146] use recommended intent filtering to allow Crosswords
to launch in response to http URLs, removing need for custom scheme and one
step from the invitation process.
---
xwords4/android/XWords4/AndroidManifest.xml | 13 ++++++++++---
xwords4/android/XWords4/res/values/common_rsrc.xml | 2 +-
2 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/xwords4/android/XWords4/AndroidManifest.xml b/xwords4/android/XWords4/AndroidManifest.xml
index 129bca3ea..12f72f4b2 100644
--- a/xwords4/android/XWords4/AndroidManifest.xml
+++ b/xwords4/android/XWords4/AndroidManifest.xml
@@ -115,15 +115,22 @@
-
+
-
+
+
+
+
+
+
+
+
diff --git a/xwords4/android/XWords4/res/values/common_rsrc.xml b/xwords4/android/XWords4/res/values/common_rsrc.xml
index e354646b6..80c92487a 100644
--- a/xwords4/android/XWords4/res/values/common_rsrc.xml
+++ b/xwords4/android/XWords4/res/values/common_rsrc.xml
@@ -104,7 +104,7 @@
http://eehouse.org/and_wordlists
- //%1$s/newgame.php
+ //%1$s/and
Update checks URL
http://eehouse.org/xw4/info.py
From 9130c8da502d0da7579f22945035094d2f098db0 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Mon, 26 Nov 2012 07:40:45 -0800
Subject: [PATCH 059/146] download and install upgrade .apk files where
possible. Download is via the existing DictImportActivity, which should also
be used for dict upgrade downloads to keep the UI consistent.
---
.../android/xw4/DictImportActivity.java | 101 ++++++++++++++----
.../org/eehouse/android/xw4/DictUtils.java | 2 +-
.../android/xw4/UpdateCheckReceiver.java | 29 ++++-
.../src/org/eehouse/android/xw4/Utils.java | 27 +++++
.../org/eehouse/android/xw4/XWConstants.java | 3 +
5 files changed, 135 insertions(+), 27 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictImportActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictImportActivity.java
index cb2cdd638..b173800f6 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictImportActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictImportActivity.java
@@ -21,31 +21,43 @@
package org.eehouse.android.xw4;
import android.app.Activity;
-import android.os.Bundle;
-import android.os.AsyncTask;
import android.content.Intent;
import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
import android.view.Window;
import android.widget.ProgressBar;
import android.widget.TextView;
-import java.io.InputStream;
import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
import java.net.URI;
import junit.framework.Assert;
public class DictImportActivity extends XWActivity {
+ public static final String APK_EXTRA = "APK";
+
private class DownloadFilesTask extends AsyncTask {
private String m_saved = null;
+ private boolean m_isApp = false;
+ private File m_appFile = null;
+
+ public DownloadFilesTask( boolean isApp )
+ {
+ super();
+ m_isApp = isApp;
+ }
+
@Override
protected Long doInBackground( Uri... uris )
{
m_saved = null;
+ m_appFile = null;
int count = uris.length;
Assert.assertTrue( 1 == count );
- long totalSize = 0;
for ( int ii = 0; ii < count; ii++ ) {
Uri uri = uris[ii];
DbgUtils.logf( "trying %s", uri );
@@ -55,7 +67,12 @@ public class DictImportActivity extends XWActivity {
uri.getSchemeSpecificPart(),
uri.getFragment() );
InputStream is = jUri.toURL().openStream();
- m_saved = saveDict( is, uri.getPath() );
+ String name = basename( uri.getPath() );
+ if ( m_isApp ) {
+ m_appFile = saveToDownloads( is, name );
+ } else {
+ m_saved = saveDict( is, name );
+ }
is.close();
} catch ( java.net.URISyntaxException use ) {
DbgUtils.loge( use );
@@ -65,7 +82,7 @@ public class DictImportActivity extends XWActivity {
DbgUtils.loge( ioe );
}
}
- return totalSize;
+ return new Long(0);
}
@Override
@@ -77,6 +94,10 @@ public class DictImportActivity extends XWActivity {
XWPrefs.getDefaultLoc( DictImportActivity.this );
DictLangCache.inval( DictImportActivity.this, m_saved,
loc, true );
+ } else if ( null != m_appFile ) {
+ // launch the installer
+ Intent intent = Utils.makeInstallIntent( m_appFile );
+ startActivity( intent );
}
finish();
}
@@ -86,6 +107,7 @@ public class DictImportActivity extends XWActivity {
protected void onCreate( Bundle savedInstanceState )
{
super.onCreate( savedInstanceState );
+ DownloadFilesTask dft = null;
requestWindowFeature( Window.FEATURE_LEFT_ICON );
setContentView( R.layout.import_dict );
@@ -96,27 +118,60 @@ public class DictImportActivity extends XWActivity {
Intent intent = getIntent();
Uri uri = intent.getData();
- if ( null != uri) {
- if ( null != intent.getType()
- && intent.getType().equals( "application/x-xwordsdict" ) ) {
- DbgUtils.logf( "based on MIME type" );
- new DownloadFilesTask().execute( uri );
- } else if ( uri.toString().endsWith( XWConstants.DICT_EXTN ) ) {
- String txt = getString( R.string.downloading_dictf,
- basename( uri.getPath()) );
- TextView view = (TextView)findViewById( R.id.dwnld_message );
- view.setText( txt );
- new DownloadFilesTask().execute( uri );
- } else {
- DbgUtils.logf( "bogus intent: %s/%s", intent.getType(), uri );
- finish();
- }
+ if ( null == uri ) {
+ String url = intent.getStringExtra( APK_EXTRA );
+ if ( null != url ) {
+ dft = new DownloadFilesTask( true );
+ uri = Uri.parse(url);
+ }
+ } else if ( null != intent.getType()
+ && intent.getType().equals( "application/x-xwordsdict" ) ) {
+ dft = new DownloadFilesTask( false );
+ } else if ( uri.toString().endsWith( XWConstants.DICT_EXTN ) ) {
+ String txt = getString( R.string.downloading_dictf,
+ basename( uri.getPath()) );
+ TextView view = (TextView)findViewById( R.id.dwnld_message );
+ view.setText( txt );
+ dft = new DownloadFilesTask( false );
+ }
+
+ if ( null == dft ) {
+ finish();
+ } else {
+ dft.execute( uri );
}
}
- private String saveDict( InputStream inputStream, String path )
+ private File saveToDownloads( InputStream is, String name )
+ {
+ boolean success = false;
+ File appFile = new File( DictUtils.getDownloadDir( this ), name );
+ Assert.assertNotNull( appFile );
+
+ byte[] buf = new byte[1024*4];
+ try {
+ FileOutputStream fos = new FileOutputStream( appFile );
+ int nRead;
+ while ( 0 <= (nRead = is.read( buf, 0, buf.length )) ) {
+ fos.write( buf, 0, nRead );
+ }
+ fos.close();
+ success = true;
+ } catch ( java.io.FileNotFoundException fnf ) {
+ DbgUtils.loge( fnf );
+ } catch ( java.io.IOException ioe ) {
+ DbgUtils.loge( ioe );
+ }
+
+ if ( !success ) {
+ appFile.delete();
+ appFile = null;
+ }
+ return appFile;
+ }
+
+ private String saveDict( InputStream inputStream, String name )
{
- String name = basename( path );
DictUtils.DictLoc loc = XWPrefs.getDefaultLoc( this );
if ( !DictUtils.saveDict( this, inputStream, name, loc ) ) {
name = null;
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java
index bfef92453..126410cfd 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java
@@ -566,7 +566,7 @@ public class DictUtils {
return null != getDownloadDir( context );
}
- private static File getDownloadDir( Context context )
+ public static File getDownloadDir( Context context )
{
File result = null;
if ( haveWriteableSD() ) {
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/UpdateCheckReceiver.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/UpdateCheckReceiver.java
index 6334230e4..f91908d4c 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/UpdateCheckReceiver.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/UpdateCheckReceiver.java
@@ -29,6 +29,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.SystemClock;
+import java.io.File;
import java.util.ArrayList;
import java.util.List;
@@ -174,11 +175,33 @@ public class UpdateCheckReceiver extends BroadcastReceiver {
if ( jobj.has( k_APP ) ) {
JSONObject app = jobj.getJSONObject( k_APP );
if ( app.has( k_URL ) ) {
- String url = app.getString( k_URL );
ApplicationInfo ai = pm.getApplicationInfo( packageName, 0);
String label = pm.getApplicationLabel( ai ).toString();
- Intent intent =
- new Intent( Intent.ACTION_VIEW, Uri.parse(url) );
+
+ // If there's a download dir AND an installer
+ // app, handle this ourselves. Otherwise just
+ // launch the browser
+ boolean useBrowser;
+ File downloads = DictUtils.getDownloadDir( context );
+ if ( null == downloads ) {
+ useBrowser = true;
+ } else {
+ File tmp = new File( downloads,
+ "xx" + XWConstants.APK_EXTN );
+ useBrowser = !Utils.canInstall( context, tmp );
+ }
+
+ Intent intent;
+ String url = app.getString( k_URL );
+ if ( useBrowser ) {
+ intent = new Intent( Intent.ACTION_VIEW,
+ Uri.parse(url) );
+ } else {
+ intent = new Intent( context,
+ DictImportActivity.class );
+ intent.putExtra( DictImportActivity.APK_EXTRA, url );
+ }
+
String title =
Utils.format( context, R.string.new_app_availf, label );
String body = context.getString( R.string.new_app_avail );
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/Utils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/Utils.java
index 9ef369196..bc823efc0 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/Utils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/Utils.java
@@ -32,6 +32,8 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences.Editor;
import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.database.Cursor;
import android.net.Uri;
@@ -43,8 +45,10 @@ import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
+import java.io.File;
import java.util.Date;
import java.util.HashMap;
+import java.util.List;
import java.util.Random;
import junit.framework.Assert;
@@ -419,6 +423,29 @@ public class Utils {
return null == s_appVersion? 0 : s_appVersion;
}
+ public static Intent makeInstallIntent( File file )
+ {
+ Uri uri = Uri.parse( "file:/" + file.getPath() );
+ Intent intent = new Intent( Intent.ACTION_VIEW );
+ intent.setDataAndType( uri, XWConstants.APK_TYPE );
+ intent.addFlags( Intent.FLAG_ACTIVITY_NEW_TASK );
+ return intent;
+ }
+
+ // Return whether there's an app installed that can install
+ public static boolean canInstall( Context context, File path )
+ {
+ boolean result = false;
+ PackageManager pm = context.getPackageManager();
+ Intent intent = makeInstallIntent( path );
+ List doers =
+ pm.queryIntentActivities( intent,
+ PackageManager.MATCH_DEFAULT_ONLY );
+ result = 0 < doers.size();
+ DbgUtils.logf( "canInstall()=>%b", result );
+ return result;
+ }
+
private static void setFirstBootStatics( Context context )
{
int thisVersion = getAppVersion( context );
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWConstants.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWConstants.java
index 9dee0732b..456f8fff6 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWConstants.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWConstants.java
@@ -23,4 +23,7 @@ package org.eehouse.android.xw4;
public interface XWConstants {
public static final String GAME_EXTN = ".xwg";
public static final String DICT_EXTN = ".xwd";
+ public static final String APK_EXTN = ".apk";
+ public static final String APK_TYPE =
+ "application/vnd.android.package-archive";
}
From e590db5f3ff4cd0b2f3b609488d3400d46eb3cf0 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Mon, 26 Nov 2012 08:05:05 -0800
Subject: [PATCH 060/146] merge in the db part of
82c39489f0b8b755b5e53f38ae1ca6b205c446fe (android_groups branch, local only
right now), but not the UI part since it won't make the next release.
---
.../XWords4/res/values/common_rsrc.xml | 1 +
.../android/XWords4/res/values/strings.xml | 3 ++
.../src/org/eehouse/android/xw4/DBHelper.java | 47 ++++++++++++++--
.../src/org/eehouse/android/xw4/DBUtils.java | 53 +++++++++----------
.../src/org/eehouse/android/xw4/XWPrefs.java | 30 +++++++++++
5 files changed, 103 insertions(+), 31 deletions(-)
diff --git a/xwords4/android/XWords4/res/values/common_rsrc.xml b/xwords4/android/XWords4/res/values/common_rsrc.xml
index 80c92487a..c7369a101 100644
--- a/xwords4/android/XWords4/res/values/common_rsrc.xml
+++ b/xwords4/android/XWords4/res/values/common_rsrc.xml
@@ -71,6 +71,7 @@
key_gcmvers_regid
key_relay_regid
key_checked_sms
+ key_default_group
key_notagain_sync
key_notagain_chat
diff --git a/xwords4/android/XWords4/res/values/strings.xml b/xwords4/android/XWords4/res/values/strings.xml
index f3da657ee..5dd2c83ef 100644
--- a/xwords4/android/XWords4/res/values/strings.xml
+++ b/xwords4/android/XWords4/res/values/strings.xml
@@ -2137,4 +2137,7 @@
(Not in external/sdcard memory)
Downloads Directory
+
+ My games
+ New games
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java
index 24e406b87..b44021f29 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java
@@ -20,9 +20,10 @@
package org.eehouse.android.xw4;
+import android.content.ContentValues;
import android.content.Context;
-import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
public class DBHelper extends SQLiteOpenHelper {
@@ -30,8 +31,9 @@ public class DBHelper extends SQLiteOpenHelper {
public static final String TABLE_NAME_OBITS = "obits";
public static final String TABLE_NAME_DICTBROWSE = "dictbrowse";
public static final String TABLE_NAME_DICTINFO = "dictinfo";
+ public static final String TABLE_NAME_GROUPS = "groups";
private static final String DB_NAME = "xwdb";
- private static final int DB_VERSION = 14;
+ private static final int DB_VERSION = 15;
public static final String GAME_NAME = "GAME_NAME";
public static final String NUM_MOVES = "NUM_MOVES";
@@ -60,7 +62,7 @@ public class DBHelper extends SQLiteOpenHelper {
public static final String SEED = "SEED";
public static final String SMSPHONE = "SMSPHONE";
public static final String LASTMOVE = "LASTMOVE";
-
+ public static final String GROUPID = "GROUPID";
public static final String DICTNAME = "DICTNAME";
public static final String MD5SUM = "MD5SUM";
@@ -76,6 +78,11 @@ public class DBHelper extends SQLiteOpenHelper {
public static final String CREATE_TIME = "CREATE_TIME";
public static final String LASTPLAY_TIME = "LASTPLAY_TIME";
+ public static final String GROUPNAME = "GROUPNAME";
+ public static final String EXPANDED = "EXPANDED";
+
+ private Context m_context;
+
private static final String[] s_summaryColsAndTypes = {
GAME_NAME, "TEXT"
,NUM_MOVES, "INTEGER"
@@ -99,6 +106,7 @@ public class DBHelper extends SQLiteOpenHelper {
,GAMEID, "INTEGER"
,REMOTEDEVS, "TEXT"
,LASTMOVE, "INTEGER DEFAULT 0"
+ ,GROUPID, "INTEGER"
// HASMSGS: sqlite doesn't have bool; use 0 and 1
,HASMSGS, "INTEGER DEFAULT 0"
,CONTRACTED, "INTEGER DEFAULT 0"
@@ -131,9 +139,15 @@ public class DBHelper extends SQLiteOpenHelper {
,ITERPREFIX, "TEXT"
};
+ private static final String[] s_groupsSchema = {
+ GROUPNAME, "TEXT"
+ ,EXPANDED, "INTEGER(1)"
+ };
+
public DBHelper( Context context )
{
super( context, DB_NAME, null, DB_VERSION );
+ m_context = context;
}
public static String getDBName()
@@ -148,6 +162,7 @@ public class DBHelper extends SQLiteOpenHelper {
createTable( db, TABLE_NAME_OBITS, s_obitsColsAndTypes );
createTable( db, TABLE_NAME_DICTINFO, s_dictInfoColsAndTypes );
createTable( db, TABLE_NAME_DICTBROWSE, s_dictBrowseColsAndTypes );
+ createGroupsTable( db );
}
@Override
@@ -177,9 +192,11 @@ public class DBHelper extends SQLiteOpenHelper {
case 12:
createTable( db, TABLE_NAME_DICTINFO, s_dictInfoColsAndTypes );
createTable( db, TABLE_NAME_DICTBROWSE, s_dictBrowseColsAndTypes );
-
case 13:
addSumColumn( db, LASTMOVE );
+ case 14:
+ addSumColumn( db, GROUPID );
+ createGroupsTable( db );
// nothing yet
break;
default:
@@ -221,4 +238,26 @@ public class DBHelper extends SQLiteOpenHelper {
db.execSQL( query.toString() );
}
+ private void createGroupsTable( SQLiteDatabase db )
+ {
+ createTable( db, TABLE_NAME_GROUPS, s_groupsSchema );
+
+ // Create an empty group name
+ ContentValues values = new ContentValues();
+ values.put( GROUPNAME, m_context.getString(R.string.group_cur_games) );
+ values.put( EXPANDED, 1 );
+ long curGroup = db.insert( TABLE_NAME_GROUPS, null, values );
+ values = new ContentValues();
+ values.put( GROUPNAME, m_context.getString(R.string.group_new_games) );
+ values.put( EXPANDED, 0 );
+ long newGroup = db.insert( TABLE_NAME_GROUPS, null, values );
+
+ // place all existing games in the initial unnamed group
+ values = new ContentValues();
+ values.put( GROUPID, curGroup );
+ db.update( DBHelper.TABLE_NAME_SUM, values, null, null );
+
+ XWPrefs.setDefaultNewGameGroup( m_context, newGroup );
+ }
+
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
index 8b9473d5f..72b8338e4 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
@@ -364,18 +364,9 @@ public class DBUtils {
private static void setInt( long rowid, String column, int value )
{
- synchronized( s_dbHelper ) {
- SQLiteDatabase db = s_dbHelper.getWritableDatabase();
-
- String selection = String.format( ROW_ID_FMT, rowid );
- ContentValues values = new ContentValues();
- values.put( column, value );
-
- int result = db.update( DBHelper.TABLE_NAME_SUM,
- values, selection, null );
- Assert.assertTrue( result == 1 );
- db.close();
- }
+ ContentValues values = new ContentValues();
+ values.put( column, value );
+ updateRow( null, DBHelper.TABLE_NAME_SUM, rowid, values );
}
public static void setMsgFlags( long rowid, int flags )
@@ -693,6 +684,8 @@ public class DBUtils {
long timestamp = new Date().getTime();
values.put( DBHelper.CREATE_TIME, timestamp );
values.put( DBHelper.LASTPLAY_TIME, timestamp );
+ values.put( DBHelper.GROUPID,
+ XWPrefs.getDefaultNewGameGroup( context ) );
long rowid = db.insert( DBHelper.TABLE_NAME_SUM, null, values );
@@ -840,21 +833,9 @@ public class DBUtils {
public static void setName( Context context, long rowid, String name )
{
- initDB( context );
- synchronized( s_dbHelper ) {
- SQLiteDatabase db = s_dbHelper.getWritableDatabase();
-
- String selection = String.format( ROW_ID_FMT, rowid );
- ContentValues values = new ContentValues();
- values.put( DBHelper.GAME_NAME, name );
-
- int result = db.update( DBHelper.TABLE_NAME_SUM,
- values, selection, null );
- db.close();
- if ( 0 == result ) {
- DbgUtils.logf( "setName(%d,%s) failed", rowid, name );
- }
- }
+ ContentValues values = new ContentValues();
+ values.put( DBHelper.GAME_NAME, name );
+ updateRow( context, DBHelper.TABLE_NAME_SUM, rowid, values );
}
public static HistoryPair[] getChatHistory( Context context, long rowid )
@@ -874,6 +855,23 @@ public class DBUtils {
return result;
}
+ 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 String getChatHistoryStr( Context context, long rowid )
{
String result = null;
@@ -1220,6 +1218,7 @@ public class DBUtils {
private static void initDB( Context context )
{
if ( null == s_dbHelper ) {
+ Assert.assertNotNull( context );
s_dbHelper = new DBHelper( context );
// force any upgrade
s_dbHelper.getWritableDatabase().close();
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWPrefs.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWPrefs.java
index 4ac4561c0..c6ef8481a 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWPrefs.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWPrefs.java
@@ -151,6 +151,25 @@ public class XWPrefs {
editor.commit();
}
+ public static long getPrefsLong( Context context, int keyID,
+ long defaultValue )
+ {
+ String key = context.getString( keyID );
+ SharedPreferences sp = PreferenceManager
+ .getDefaultSharedPreferences( context );
+ return sp.getLong( key, defaultValue );
+ }
+
+ public static void setPrefsLong( Context context, int keyID, long newVal )
+ {
+ SharedPreferences sp = PreferenceManager
+ .getDefaultSharedPreferences( context );
+ SharedPreferences.Editor editor = sp.edit();
+ String key = context.getString( keyID );
+ editor.putLong( key, newVal );
+ editor.commit();
+ }
+
public static void setClosedLangs( Context context, String[] langs )
{
setPrefsString( context, R.string.key_closed_langs,
@@ -275,6 +294,17 @@ public class XWPrefs {
return getPrefsBoolean( context, R.string.key_default_loc, true );
}
+ public static long getDefaultNewGameGroup( Context context )
+ {
+ return getPrefsLong( context, R.string.key_default_group,
+ DBUtils.ROWID_NOTFOUND );
+ }
+
+ public static void setDefaultNewGameGroup( Context context, long val )
+ {
+ setPrefsLong( context, R.string.key_default_group, val );
+ }
+
protected static String getPrefsString( Context context, int keyID )
{
String key = context.getString( keyID );
From b4334380220b64fb300fd15c2154166f2f338ed8 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Mon, 26 Nov 2012 18:47:35 -0800
Subject: [PATCH 061/146] add message via GCM to check for wordlist/app
upgrades
---
.../eehouse/android/xw4/GCMIntentService.java | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GCMIntentService.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GCMIntentService.java
index 1fc22e503..532e70329 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GCMIntentService.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GCMIntentService.java
@@ -56,7 +56,18 @@ public class GCMIntentService extends GCMBaseIntentService {
@Override
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 ) {
String title = intent.getStringExtra( "title" );
if ( null != title ) {
@@ -64,11 +75,6 @@ public class GCMIntentService extends GCMBaseIntentService {
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 )
From b1f54a67ed441c47e8f7f2b47a676a52cdda1648 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Mon, 26 Nov 2012 20:14:32 -0800
Subject: [PATCH 062/146] end path prefix with a /; otherwise Crosswords gets
launched to browse the wordlist directory.
---
xwords4/android/XWords4/AndroidManifest.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/xwords4/android/XWords4/AndroidManifest.xml b/xwords4/android/XWords4/AndroidManifest.xml
index 12f72f4b2..c106e32f6 100644
--- a/xwords4/android/XWords4/AndroidManifest.xml
+++ b/xwords4/android/XWords4/AndroidManifest.xml
@@ -129,7 +129,7 @@
+ android:host="eehouse.org" android:pathPrefix="/and/" />
From 30377908df000146079baa74be2a7f039559bc05 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Mon, 26 Nov 2012 20:19:25 -0800
Subject: [PATCH 063/146] Use the downloader with an infinite progress
indicator instead of the status-bar notifier (which is removed) for dict
downloads.
---
.../eehouse/android/xw4/BoardActivity.java | 13 +--
.../android/xw4/DictImportActivity.java | 95 +++++++++++++++++--
.../eehouse/android/xw4/DictsActivity.java | 12 +--
.../org/eehouse/android/xw4/GamesList.java | 15 +--
.../src/org/eehouse/android/xw4/NetUtils.java | 74 ---------------
.../eehouse/android/xw4/StatusNotifier.java | 58 -----------
6 files changed, 108 insertions(+), 159 deletions(-)
delete mode 100644 xwords4/android/XWords4/src/org/eehouse/android/xw4/StatusNotifier.java
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
index e45f64e3e..6b2f35f51 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
@@ -57,7 +57,7 @@ import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole;
public class BoardActivity extends XWActivity
implements TransportProcs.TPMsgHandler, View.OnClickListener,
- NetUtils.DownloadFinishedListener {
+ DictImportActivity.DownloadFinishedListener {
public static final String INTENT_KEY_CHAT = "chat";
@@ -259,10 +259,11 @@ public class BoardActivity extends XWActivity
if ( DLG_USEDICT == id ) {
setGotGameDict( m_getDict );
} else {
- NetUtils.downloadDictInBack( BoardActivity.this,
- m_gi.dictLang,
- m_getDict,
- BoardActivity.this );
+ DictImportActivity
+ .downloadDictInBack( BoardActivity.this,
+ m_gi.dictLang,
+ 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 )
{
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictImportActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictImportActivity.java
index b173800f6..a01e68d43 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictImportActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictImportActivity.java
@@ -21,6 +21,7 @@
package org.eehouse.android.xw4;
import android.app.Activity;
+import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
@@ -32,15 +33,36 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URI;
+import java.util.HashMap;
import junit.framework.Assert;
public class DictImportActivity extends XWActivity {
+ // URIs coming in in intents
public 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 s_listeners =
+ new HashMap();
private class DownloadFilesTask extends AsyncTask {
- private String m_saved = null;
+ private String m_savedDict = null;
+ private String m_url = null;
private boolean m_isApp = false;
private File m_appFile = null;
@@ -50,10 +72,16 @@ public class DictImportActivity extends XWActivity {
m_isApp = isApp;
}
+ public DownloadFilesTask( String url, boolean isApp )
+ {
+ this( isApp );
+ m_url = url;
+ }
+
@Override
protected Long doInBackground( Uri... uris )
{
- m_saved = null;
+ m_savedDict = null;
m_appFile = null;
int count = uris.length;
@@ -71,7 +99,7 @@ public class DictImportActivity extends XWActivity {
if ( m_isApp ) {
m_appFile = saveToDownloads( is, name );
} else {
- m_saved = saveDict( is, name );
+ m_savedDict = saveDict( is, name );
}
is.close();
} catch ( java.net.URISyntaxException use ) {
@@ -89,15 +117,19 @@ public class DictImportActivity extends XWActivity {
protected void onPostExecute( Long result )
{
DbgUtils.logf( "onPostExecute passed %d", result );
- if ( null != m_saved ) {
+ if ( null != m_savedDict ) {
DictUtils.DictLoc loc =
XWPrefs.getDefaultLoc( DictImportActivity.this );
- DictLangCache.inval( DictImportActivity.this, m_saved,
+ DictLangCache.inval( DictImportActivity.this, m_savedDict,
loc, true );
+ callListener( m_url, true );
} else if ( null != m_appFile ) {
// launch the installer
Intent intent = Utils.makeInstallIntent( m_appFile );
startActivity( intent );
+ } else {
+ // we failed at something....
+ callListener( m_url, false );
}
finish();
}
@@ -120,9 +152,13 @@ public class DictImportActivity extends XWActivity {
Uri uri = intent.getData();
if ( null == uri ) {
String url = intent.getStringExtra( APK_EXTRA );
+ boolean isApp = null != url;
+ if ( !isApp ) {
+ url = intent.getStringExtra( DICT_EXTRA );
+ }
if ( null != url ) {
- dft = new DownloadFilesTask( true );
- uri = Uri.parse(url);
+ dft = new DownloadFilesTask( url, isApp );
+ uri = Uri.parse( url );
}
} else if ( null != intent.getType()
&& intent.getType().equals( "application/x-xwordsdict" ) ) {
@@ -132,7 +168,7 @@ public class DictImportActivity extends XWActivity {
basename( uri.getPath()) );
TextView view = (TextView)findViewById( R.id.dwnld_message );
view.setText( txt );
- dft = new DownloadFilesTask( false );
+ dft = new DownloadFilesTask( uri.toString(), false );
}
if ( null == dft ) {
@@ -183,6 +219,49 @@ public class DictImportActivity extends XWActivity {
{
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 );
+ }
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictsActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictsActivity.java
index e56b37559..b3f3331ff 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictsActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictsActivity.java
@@ -61,7 +61,7 @@ import org.eehouse.android.xw4.DictUtils.DictLoc;
public class DictsActivity extends ExpandableListActivity
implements View.OnClickListener, XWListItem.DeleteCallback,
MountEventReceiver.SDCardNotifiee, DlgDelegate.DlgClickNotify,
- NetUtils.DownloadFinishedListener {
+ DictImportActivity.DownloadFinishedListener {
private static final String DICT_DOLAUNCH = "do_launch";
private static final String DICT_LANG_EXTRA = "use_lang";
@@ -339,8 +339,9 @@ public class DictsActivity extends ExpandableListActivity
String name = intent.getStringExtra( MultiService.DICT );
m_launchedForMissing = true;
m_handler = new Handler();
- NetUtils.downloadDictInBack( DictsActivity.this, lang,
- name, DictsActivity.this );
+ DictImportActivity
+ .downloadDictInBack( DictsActivity.this, lang,
+ name, DictsActivity.this );
}
};
lstnr2 = new OnClickListener() {
@@ -555,10 +556,9 @@ public class DictsActivity extends ExpandableListActivity
{
int loci = intent.getIntExtra( UpdateCheckReceiver.NEW_DICT_LOC, 0 );
if ( 0 < loci ) {
- DictLoc loc = DictLoc.values()[loci];
String url =
intent.getStringExtra( UpdateCheckReceiver.NEW_DICT_URL );
- NetUtils.downloadDictInBack( this, url, loc, null );
+ DictImportActivity.downloadDictInBack( this, url );
finish();
}
}
@@ -769,7 +769,7 @@ public class DictsActivity extends ExpandableListActivity
launchAndDownload( activity, 0, null );
}
- // NetUtils.DownloadFinishedListener interface
+ // DictImportActivity.DownloadFinishedListener interface
public void downloadFinished( String name, final boolean success )
{
if ( m_launchedForMissing ) {
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
index b9975a6e6..bebe25437 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
@@ -54,7 +54,7 @@ public class GamesList extends XWListActivity
implements DispatchNotify.HandleRelaysIface,
DBUtils.DBChangeListener,
GameListAdapter.LoadItemCB,
- NetUtils.DownloadFinishedListener {
+ DictImportActivity.DownloadFinishedListener {
private static final int WARN_NODICT = DlgDelegate.DIALOG_LAST + 1;
private static final int WARN_NODICT_SUBST = WARN_NODICT + 1;
@@ -103,15 +103,16 @@ public class GamesList extends XWListActivity
case WARN_NODICT_SUBST:
lstnr = new DialogInterface.OnClickListener() {
public void onClick( DialogInterface dlg, int item ) {
- // just do one
+ // no name, so user must pick
if ( null == m_missingDictName ) {
DictsActivity.launchAndDownload( GamesList.this,
m_missingDictLang );
} else {
- NetUtils.downloadDictInBack( GamesList.this,
- m_missingDictLang,
- m_missingDictName,
- GamesList.this );
+ DictImportActivity
+ .downloadDictInBack( GamesList.this,
+ m_missingDictLang,
+ m_missingDictName,
+ GamesList.this );
}
}
};
@@ -623,7 +624,7 @@ public class GamesList extends XWListActivity
return handled;
}
- // NetUtils.DownloadFinishedListener interface
+ // DictImportActivity.DownloadFinishedListener interface
public void downloadFinished( String name, final boolean success )
{
post( new Runnable() {
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetUtils.java
index 64c12f3d7..4f900a76d 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetUtils.java
@@ -21,17 +21,11 @@
package org.eehouse.android.xw4;
import android.content.Context;
-import android.os.Handler;
-import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.Socket;
-import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
@@ -50,10 +44,6 @@ public class NetUtils {
public static byte PRX_GET_MSGS = 4;
public static byte PRX_PUT_MSGS = 5;
- public interface DownloadFinishedListener {
- void downloadFinished( String name, boolean success );
- }
-
public static Socket makeProxySocket( Context context,
int timeoutMillis )
{
@@ -273,68 +263,4 @@ public class NetUtils {
DbgUtils.logf( "sendToRelay: null msgs" );
}
} // 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();
- }
-
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/StatusNotifier.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/StatusNotifier.java
deleted file mode 100644
index 6fa126c6e..000000000
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/StatusNotifier.java
+++ /dev/null
@@ -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 );
- }
-
-}
From f3ecfa569a24f027a404db9594db834f76912702 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Tue, 27 Nov 2012 07:02:44 -0800
Subject: [PATCH 064/146] get rid of the second URL in invites that's meant for
those without the app installed. It's confusing, especially in SMS case, and
the page they see when they don't have the app installed can explain how to
install it.
---
xwords4/android/XWords4/res/values/strings.xml | 17 ++++-------------
1 file changed, 4 insertions(+), 13 deletions(-)
diff --git a/xwords4/android/XWords4/res/values/strings.xml b/xwords4/android/XWords4/res/values/strings.xml
index 5dd2c83ef..514732fb1 100644
--- a/xwords4/android/XWords4/res/values/strings.xml
+++ b/xwords4/android/XWords4/res/values/strings.xml
@@ -1229,27 +1229,18 @@
encodings for the greater-than and less-than symbols which
are not legal in xml strings.)-->
\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.
\u003cbr \\\u003E
\u003cbr \\\u003E
- (raw 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)
+ (full link: %1$s)
- Play Crosswords? Join this game: %1$s
- . (But install Crosswords http://eehouse.org/market_redir.php
- first if you haven\'t.)
+ Let\'s play Crosswords! Join this game:
+ %1$s .
+ eehouse.org
http://eehouse.org/and_wordlists
//%1$s/and
Update checks URL
diff --git a/xwords4/android/XWords4/res/xml/xwprefs.xml b/xwords4/android/XWords4/res/xml/xwprefs.xml
index 9a5a3bf3c..bc436be4f 100644
--- a/xwords4/android/XWords4/res/xml/xwprefs.xml
+++ b/xwords4/android/XWords4/res/xml/xwprefs.xml
@@ -324,11 +324,6 @@
android:defaultValue="10998"
android:numeric="decimal"
/>
-
Date: Tue, 27 Nov 2012 07:22:03 -0800
Subject: [PATCH 066/146] add logging giving size and md5sum of downloaded
.apk.
---
.../android/xw4/DictImportActivity.java | 21 ++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictImportActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictImportActivity.java
index a01e68d43..51e7a1dcb 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictImportActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictImportActivity.java
@@ -33,6 +33,7 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URI;
+import java.security.MessageDigest;
import java.util.HashMap;
import junit.framework.Assert;
@@ -183,16 +184,34 @@ public class DictImportActivity extends XWActivity {
boolean success = false;
File appFile = new File( DictUtils.getDownloadDir( this ), name );
Assert.assertNotNull( appFile );
-
+
+ // Get rid of this after debugging download/install problems
+ MessageDigest md;
+ try {
+ md = MessageDigest.getInstance("MD5");
+ } catch( Exception ex ) {
+ md = null;
+ }
+
byte[] buf = new byte[1024*4];
try {
+ int nTotal = 0;
FileOutputStream fos = new FileOutputStream( appFile );
int nRead;
while ( 0 <= (nRead = is.read( buf, 0, buf.length )) ) {
fos.write( buf, 0, nRead );
+ if ( null != md ) {
+ md.update( buf, 0, nRead );
+ }
+ nTotal += nRead;
}
fos.close();
success = true;
+
+ String sum = null == md ? ""
+ : Utils.digestToString( md.digest() );
+ DbgUtils.logf( "saveToDownloads: saved %d bytes to %s, md5sum=%s",
+ nTotal, appFile.getPath(), sum );
} catch ( java.io.FileNotFoundException fnf ) {
DbgUtils.loge( fnf );
} catch ( java.io.IOException ioe ) {
From bf970b6dd958cd8ad0fbf3e11c4e85354c0eb80e Mon Sep 17 00:00:00 2001
From: Eric House
Date: Tue, 27 Nov 2012 07:53:48 -0800
Subject: [PATCH 067/146] remove some logging
---
.../XWords4/src/org/eehouse/android/xw4/SMSService.java | 3 ---
1 file changed, 3 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java
index 18cbd8c88..a78ba6a7d 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java
@@ -664,11 +664,9 @@ public class SMSService extends Service {
@Override
public void onReceive(Context arg0, Intent arg1)
{
- DbgUtils.logf( "got MSG_DELIVERED" );
switch ( getResultCode() ) {
case Activity.RESULT_OK:
sendResult( MultiEvent.SMS_SEND_OK );
- DbgUtils.logf( "SUCCESS!!!" );
break;
case SmsManager.RESULT_ERROR_RADIO_OFF:
DbgUtils.showf( SMSService.this, "NO RADIO!!!" );
@@ -688,7 +686,6 @@ public class SMSService extends Service {
@Override
public void onReceive(Context arg0, Intent arg1)
{
- DbgUtils.logf( "got MSG_DELIVERED" );
if ( Activity.RESULT_OK == getResultCode() ) {
DbgUtils.logf( "SUCCESS!!!" );
} else {
From 7c5a59beb3147f8cad6afae4cf5920d4286ee1fe Mon Sep 17 00:00:00 2001
From: Eric House
Date: Tue, 27 Nov 2012 18:31:14 -0800
Subject: [PATCH 068/146] remind self of Blaze's download directory
---
xwords4/android/XWords4/res/xml/xwprefs.xml | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/xwords4/android/XWords4/res/xml/xwprefs.xml b/xwords4/android/XWords4/res/xml/xwprefs.xml
index bc436be4f..86fdece79 100644
--- a/xwords4/android/XWords4/res/xml/xwprefs.xml
+++ b/xwords4/android/XWords4/res/xml/xwprefs.xml
@@ -299,6 +299,11 @@
android:summary="Menuitems etc."
android:defaultValue="false"
/>
+
+
Date: Tue, 27 Nov 2012 18:48:05 -0800
Subject: [PATCH 069/146] fix uri format error that was causing install to fail
---
xwords4/android/XWords4/src/org/eehouse/android/xw4/Utils.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/Utils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/Utils.java
index bc823efc0..288566417 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/Utils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/Utils.java
@@ -425,7 +425,8 @@ public class Utils {
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.setDataAndType( uri, XWConstants.APK_TYPE );
intent.addFlags( Intent.FLAG_ACTIVITY_NEW_TASK );
From cd197e45307d9bb4db495df2f02df4fa16f804c6 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Tue, 27 Nov 2012 18:55:08 -0800
Subject: [PATCH 070/146] use Class instance for synchronization of static
methods rather than creating an object only for that purpose.
---
.../XWords4/src/org/eehouse/android/xw4/BoardActivity.java | 2 +-
.../XWords4/src/org/eehouse/android/xw4/ConnStatusHandler.java | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
index 6b2f35f51..8cd084c2e 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
@@ -167,7 +167,7 @@ public class BoardActivity extends XWActivity
private boolean m_haveInvited = false;
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,
CommsAddrRec retAddr )
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/ConnStatusHandler.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/ConnStatusHandler.java
index 13c973646..8ceb78a32 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/ConnStatusHandler.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/ConnStatusHandler.java
@@ -126,7 +126,7 @@ public class ConnStatusHandler {
private static HashMap s_records =
new HashMap();
- private static Object s_lockObj = new Object();
+ private static Class s_lockObj = ConnStatusHandler.class;
private static boolean s_needsSave = false;
public static void setRect( int left, int top, int right, int bottom )
From baa790a8c3e6bf468455b00312f3145cd255dab5 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Wed, 28 Nov 2012 06:06:42 -0800
Subject: [PATCH 071/146] remove debugging code; make Intent content details
private to class.
---
.../android/xw4/DictImportActivity.java | 33 +++++++------------
.../android/xw4/UpdateCheckReceiver.java | 5 ++-
2 files changed, 13 insertions(+), 25 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictImportActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictImportActivity.java
index 51e7a1dcb..1497e10a4 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictImportActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictImportActivity.java
@@ -1,7 +1,7 @@
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
- * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
- * rights reserved.
+ * Copyright 2009-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
@@ -41,7 +41,7 @@ import junit.framework.Assert;
public class DictImportActivity extends XWActivity {
// URIs coming in in intents
- public static final String APK_EXTRA = "APK";
+ private static final String APK_EXTRA = "APK";
private static final String DICT_EXTRA = "XWD";
public interface DownloadFinishedListener {
@@ -183,35 +183,16 @@ public class DictImportActivity extends XWActivity {
{
boolean success = false;
File appFile = new File( DictUtils.getDownloadDir( this ), name );
- Assert.assertNotNull( appFile );
-
- // Get rid of this after debugging download/install problems
- MessageDigest md;
- try {
- md = MessageDigest.getInstance("MD5");
- } catch( Exception ex ) {
- md = null;
- }
byte[] buf = new byte[1024*4];
try {
- int nTotal = 0;
FileOutputStream fos = new FileOutputStream( appFile );
int nRead;
while ( 0 <= (nRead = is.read( buf, 0, buf.length )) ) {
fos.write( buf, 0, nRead );
- if ( null != md ) {
- md.update( buf, 0, nRead );
- }
- nTotal += nRead;
}
fos.close();
success = true;
-
- String sum = null == md ? ""
- : Utils.digestToString( md.digest() );
- DbgUtils.logf( "saveToDownloads: saved %d bytes to %s, md5sum=%s",
- nTotal, appFile.getPath(), sum );
} catch ( java.io.FileNotFoundException fnf ) {
DbgUtils.loge( fnf );
} catch ( java.io.IOException ioe ) {
@@ -281,6 +262,14 @@ public class DictImportActivity extends XWActivity {
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;
+ }
+
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/UpdateCheckReceiver.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/UpdateCheckReceiver.java
index f91908d4c..8b69846d2 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/UpdateCheckReceiver.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/UpdateCheckReceiver.java
@@ -197,9 +197,8 @@ public class UpdateCheckReceiver extends BroadcastReceiver {
intent = new Intent( Intent.ACTION_VIEW,
Uri.parse(url) );
} else {
- intent = new Intent( context,
- DictImportActivity.class );
- intent.putExtra( DictImportActivity.APK_EXTRA, url );
+ intent = DictImportActivity
+ .makeAppDownloadIntent( context, url );
}
String title =
From 6f620ebc44054be5899a888f2b7beb8109ecc6c3 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Wed, 28 Nov 2012 06:30:35 -0800
Subject: [PATCH 072/146] move prefix into resources two since it's repeated.
---
xwords4/android/XWords4/AndroidManifest.xml | 4 +++-
.../android/XWords4/res/values/common_rsrc.xml | 3 +--
.../org/eehouse/android/xw4/NetLaunchInfo.java | 18 +++++++++---------
3 files changed, 13 insertions(+), 12 deletions(-)
diff --git a/xwords4/android/XWords4/AndroidManifest.xml b/xwords4/android/XWords4/AndroidManifest.xml
index 6e94f95a0..176d067a2 100644
--- a/xwords4/android/XWords4/AndroidManifest.xml
+++ b/xwords4/android/XWords4/AndroidManifest.xml
@@ -129,7 +129,9 @@
+ android:host="@string/invite_host"
+ android:pathPrefix="@string/invite_prefix"
+ />
diff --git a/xwords4/android/XWords4/res/values/common_rsrc.xml b/xwords4/android/XWords4/res/values/common_rsrc.xml
index e8928e6a9..516e9aa13 100644
--- a/xwords4/android/XWords4/res/values/common_rsrc.xml
+++ b/xwords4/android/XWords4/res/values/common_rsrc.xml
@@ -102,10 +102,9 @@
eehouse.org
-
eehouse.org
+ /and/
http://eehouse.org/and_wordlists
- //%1$s/and
Update checks URL
http://eehouse.org/xw4/info.py
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetLaunchInfo.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetLaunchInfo.java
index f25453dda..0fa720132 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetLaunchInfo.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetLaunchInfo.java
@@ -22,7 +22,6 @@ package org.eehouse.android.xw4;
import android.content.Context;
import android.content.Intent;
-import android.net.Uri.Builder;
import android.net.Uri;
import android.os.Bundle;
import java.net.URLEncoder;
@@ -99,14 +98,15 @@ public class NetLaunchInfo {
String inviteID, int lang,
String dict, int nPlayersT )
{
- String host = context.getString( R.string.invite_host );
- Builder ub = new Builder();
- ub.scheme( "http" );
- ub.path( context.getString( R.string.game_url_pathf, host ) );
- ub.appendQueryParameter( "lang", String.format("%d", lang ) );
- ub.appendQueryParameter( "np", String.format( "%d", nPlayersT ) );
- ub.appendQueryParameter( "room", room );
- ub.appendQueryParameter( "id", inviteID );
+ Uri.Builder ub = new Uri.Builder()
+ .scheme( "http" )
+ .path( String.format( "//%s%s",
+ context.getString(R.string.invite_host),
+ context.getString(R.string.invite_prefix) ) )
+ .appendQueryParameter( "lang", String.format("%d", lang ) )
+ .appendQueryParameter( "np", String.format( "%d", nPlayersT ) )
+ .appendQueryParameter( "room", room )
+ .appendQueryParameter( "id", inviteID );
if ( null != dict ) {
ub.appendQueryParameter( "wl", dict );
}
From 19333e33acfb7d678e2907422773b0da2a5eefbd Mon Sep 17 00:00:00 2001
From: Eric House
Date: Wed, 28 Nov 2012 19:17:29 -0800
Subject: [PATCH 073/146] fix confirmation of duplicate game from invite. Along
the way dramatically simplify how new game intents are passed around.
---
.../org/eehouse/android/xw4/BTService.java | 3 +-
.../eehouse/android/xw4/DispatchNotify.java | 165 +-----------------
.../org/eehouse/android/xw4/GamesList.java | 157 +++++++++++------
.../org/eehouse/android/xw4/RelayService.java | 6 +-
.../org/eehouse/android/xw4/SMSService.java | 3 +-
.../org/eehouse/android/xw4/XWActivity.java | 2 -
.../eehouse/android/xw4/XWListActivity.java | 2 -
7 files changed, 107 insertions(+), 231 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BTService.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BTService.java
index e146983c7..29dadf1fb 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BTService.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BTService.java
@@ -974,8 +974,7 @@ public class BTService extends Service {
private void postNotification( int gameID, int title, String body )
{
- Intent intent = new Intent( this, DispatchNotify.class );
- intent.putExtra( DispatchNotify.GAMEID_EXTRA, gameID );
+ Intent intent = GamesList.makeGameIDIntent( this, gameID );
Utils.postNotification( this, intent, R.string.new_btmove_title,
body, gameID );
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DispatchNotify.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DispatchNotify.java
index 0e0d8f9ef..c2178a99b 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DispatchNotify.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DispatchNotify.java
@@ -33,175 +33,16 @@ import org.eehouse.android.xw4.jni.GameSummary;
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 s_running =
- new HashSet();
- private static HandleRelaysIface s_handler;
-
@Override
protected void onCreate( Bundle savedInstanceState )
{
- boolean mustLaunch = false;
super.onCreate( savedInstanceState );
- String[] relayIDs = getIntent().getStringArrayExtra( RELAYIDS_EXTRA );
- int gameID = getIntent().getIntExtra( GAMEID_EXTRA, -1 );
Uri data = getIntent().getData();
-
- if ( null != relayIDs ) {
- 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 );
+ if ( null != data ) { // relay invite redirected URL case
+ GamesList.openGame( this, data );
}
finish();
- }
-
- 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;
- }
+ } // onCreate
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
index bebe25437..43028718b 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
@@ -51,8 +51,7 @@ import junit.framework.Assert;
import org.eehouse.android.xw4.jni.*;
public class GamesList extends XWListActivity
- implements DispatchNotify.HandleRelaysIface,
- DBUtils.DBChangeListener,
+ implements DBUtils.DBChangeListener,
GameListAdapter.LoadItemCB,
DictImportActivity.DownloadFinishedListener {
@@ -65,6 +64,9 @@ public class GamesList extends XWListActivity
private static final String SAVE_ROWID = "SAVE_ROWID";
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 RESET_GAME_ACTION = 2;
private static final int DELETE_GAME_ACTION = 3;
@@ -293,8 +295,7 @@ public class GamesList extends XWListActivity
{
super.onNewIntent( intent );
Assert.assertNotNull( intent );
- invalRelayIDs( intent.
- getStringArrayExtra( DispatchNotify.RELAYIDS_EXTRA ) );
+ invalRelayIDs( intent.getStringArrayExtra( RELAYIDS_EXTRA ) );
startFirstHasDict( intent );
startNewNetGame( intent );
startHasGameID( intent );
@@ -304,7 +305,6 @@ public class GamesList extends XWListActivity
protected void onStart()
{
super.onStart();
- DispatchNotify.SetRelayIDsHandler( this );
boolean hide = CommonPrefs.getHideIntro( this );
int hereOrGone = hide ? View.GONE : View.VISIBLE;
@@ -331,7 +331,6 @@ public class GamesList extends XWListActivity
// (TelephonyManager)getSystemService( Context.TELEPHONY_SERVICE );
// mgr.listen( m_phoneStateListener, PhoneStateListener.LISTEN_NONE );
// m_phoneStateListener = null;
- DispatchNotify.SetRelayIDsHandler( null );
super.onStop();
}
@@ -372,39 +371,6 @@ public class GamesList extends XWListActivity
}
}
- // 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
public void gameSaved( final long rowid )
{
@@ -474,8 +440,9 @@ public class GamesList extends XWListActivity
if ( AlertDialog.BUTTON_POSITIVE == which ) {
switch( id ) {
case NEW_NET_GAME_ACTION:
- long rowid = GameUtils.makeNewNetGame( this, m_netLaunchInfo );
- GameUtils.launchGame( this, rowid, true );
+ if ( checkWarnNoDict( m_netLaunchInfo ) ) {
+ makeNewNetGameIf();
+ }
break;
case RESET_GAME_ACTION:
GameUtils.resetGame( this, m_rowid );
@@ -629,9 +596,12 @@ public class GamesList extends XWListActivity
{
post( new Runnable() {
public void run() {
- int id = success ? R.string.download_done
- : R.string.download_failed;
- Utils.showToast( GamesList.this, id );
+ boolean madeGame = success ? makeNewNetGameIf() : false;
+ if ( ! madeGame ) {
+ int id = success ? R.string.download_done
+ : R.string.download_failed;
+ Utils.showToast( GamesList.this, id );
+ }
}
} );
}
@@ -698,6 +668,32 @@ public class GamesList extends XWListActivity
return handled;
} // handleMenuItem
+ 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 );
+ }
+ return haveDict;
+ }
+
private boolean checkWarnNoDict( long rowid )
{
String[][] missingNames = new String[1][];
@@ -764,8 +760,7 @@ public class GamesList extends XWListActivity
private void startFirstHasDict( Intent intent )
{
if ( null != intent ) {
- String[] relayIDs =
- intent.getStringArrayExtra( DispatchNotify.RELAYIDS_EXTRA );
+ String[] relayIDs = intent.getStringArrayExtra( RELAYIDS_EXTRA );
startFirstHasDict( relayIDs );
}
}
@@ -775,33 +770,34 @@ public class GamesList extends XWListActivity
startActivity( new Intent( this, NewGameActivity.class ) );
}
- private void startNewNetGame( NetLaunchInfo info )
+ private void startNewNetGame( NetLaunchInfo nli )
{
- long rowid = DBUtils.getRowIDForOpen( this, info );
+ long rowid = DBUtils.getRowIDForOpen( this, nli );
if ( DBUtils.ROWID_NOTFOUND == rowid ) {
- rowid = GameUtils.makeNewNetGame( this, info );
- GameUtils.launchGame( this, rowid, true );
+ if ( checkWarnNoDict( nli ) ) {
+ makeNewNetGame( nli );
+ }
} else {
- String msg = getString( R.string.dup_game_queryf, info.room );
- m_netLaunchInfo = info;
+ String msg = getString( R.string.dup_game_queryf, nli.room );
+ m_netLaunchInfo = nli;
showConfirmThen( msg, NEW_NET_GAME_ACTION );
}
} // startNewNetGame
private void startNewNetGame( Intent intent )
{
- NetLaunchInfo info = null;
+ NetLaunchInfo nli = null;
if ( MultiService.isMissingDictIntent( intent ) ) {
- info = new NetLaunchInfo( intent );
+ nli = new NetLaunchInfo( intent );
} else {
Uri data = intent.getData();
if ( null != data ) {
- info = new NetLaunchInfo( data );
+ nli = new NetLaunchInfo( data );
}
}
- if ( null != info && info.isValid() ) {
- startNewNetGame( info );
+ if ( null != nli && nli.isValid() ) {
+ startNewNetGame( nli );
}
} // startNewNetGame
@@ -815,7 +811,7 @@ public class GamesList extends XWListActivity
private void startHasGameID( Intent intent )
{
- int gameID = intent.getIntExtra( DispatchNotify.GAMEID_EXTRA, 0 );
+ int gameID = intent.getIntExtra( GAMEID_EXTRA, 0 );
if ( 0 != gameID ) {
startHasGameID( gameID );
}
@@ -840,10 +836,55 @@ public class GamesList extends XWListActivity
}
}
+ private boolean makeNewNetGameIf()
+ {
+ boolean madeGame = null != m_netLaunchInfo;
+ if ( madeGame ) {
+ makeNewNetGame( m_netLaunchInfo );
+ m_netLaunchInfo = null;
+ }
+ 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 )
{
intent.setClass( context, GamesList.class );
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 );
+ }
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayService.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayService.java
index a744ba8b9..f2c33dc70 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayService.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayService.java
@@ -63,9 +63,9 @@ public class RelayService extends Service {
long[] rowids = DBUtils.getRowIDsFor( this, relayID );
if ( null != rowids ) {
for ( long rowid : rowids ) {
- Intent intent = new Intent( this, DispatchNotify.class );
- intent.putExtra( DispatchNotify.RELAYIDS_EXTRA,
- new String[] {relayID} );
+ Intent intent =
+ GamesList.makeRelayIdsIntent( this,
+ new String[] {relayID} );
String msg = Utils.format( this, R.string.notify_bodyf,
GameUtils.getName( this, rowid ) );
Utils.postNotification( this, intent, R.string.notify_title,
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java
index a78ba6a7d..0706ab878 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java
@@ -617,8 +617,7 @@ public class SMSService extends Service {
private void postNotification( int gameID, int title, String body )
{
- Intent intent = new Intent( this, DispatchNotify.class );
- intent.putExtra( DispatchNotify.GAMEID_EXTRA, gameID );
+ Intent intent = GamesList.makeGameIDIntent( this, gameID );
Utils.postNotification( this, intent, title, body, gameID );
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWActivity.java
index b97d82ed5..18670d379 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWActivity.java
@@ -48,7 +48,6 @@ public class XWActivity extends Activity
{
DbgUtils.logf( "%s.onStart(this=%H)", getClass().getName(), this );
super.onStart();
- DispatchNotify.SetRunning( this );
}
@Override
@@ -73,7 +72,6 @@ public class XWActivity extends Activity
protected void onStop()
{
DbgUtils.logf( "%s.onStop(this=%H)", getClass().getName(), this );
- DispatchNotify.ClearRunning( this );
super.onStop();
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListActivity.java
index 397085e70..9f10da3d4 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListActivity.java
@@ -45,7 +45,6 @@ public class XWListActivity extends ListActivity
{
DbgUtils.logf( "%s.onStart(this=%H)", getClass().getName(), this );
super.onStart();
- DispatchNotify.SetRunning( this );
}
@Override
@@ -70,7 +69,6 @@ public class XWListActivity extends ListActivity
protected void onStop()
{
DbgUtils.logf( "%s.onStop(this=%H)", getClass().getName(), this );
- DispatchNotify.ClearRunning( this );
super.onStop();
}
From 4bae56e6316313ddff2c6d8b329b01210ef9e4ae Mon Sep 17 00:00:00 2001
From: Eric House
Date: Wed, 28 Nov 2012 19:32:50 -0800
Subject: [PATCH 074/146] use rowid as notification id for all types of games,
and cancel when games deleted.
---
.../org/eehouse/android/xw4/BTService.java | 13 ++++++-----
.../eehouse/android/xw4/BoardActivity.java | 22 +------------------
.../org/eehouse/android/xw4/GameUtils.java | 1 +
.../org/eehouse/android/xw4/RelayService.java | 2 +-
.../org/eehouse/android/xw4/SMSService.java | 14 +++++++-----
.../src/org/eehouse/android/xw4/Utils.java | 3 ++-
6 files changed, 20 insertions(+), 35 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BTService.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BTService.java
index 29dadf1fb..f62100c4e 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BTService.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BTService.java
@@ -444,7 +444,7 @@ public class BTService extends Service {
result = BTCmd.INVITE_ACCPT;
String body = Utils.format( BTService.this,
R.string.new_bt_bodyf, sender );
- postNotification( gameID, R.string.new_bt_title, body );
+ postNotification( gameID, R.string.new_bt_title, body, rowid );
}
} else {
result = BTCmd.INVITE_DUPID;
@@ -497,7 +497,7 @@ public class BTService extends Service {
buffer, addr,
m_btMsgSink ) ) {
postNotification( gameID, R.string.new_btmove_title,
- R.string.new_move_body );
+ R.string.new_move_body, rowid );
// do nothing
} else {
DbgUtils.logf( "nobody took msg for gameID %X",
@@ -967,16 +967,17 @@ public class BTService extends Service {
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 = GamesList.makeGameIDIntent( this, gameID );
Utils.postNotification( this, intent, R.string.new_btmove_title,
- body, gameID );
+ body, (int)rowid );
}
private Thread killSocketIn( final BluetoothSocket socket )
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
index 8cd084c2e..cdbd49cab 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
@@ -1732,7 +1732,7 @@ public class BoardActivity extends XWActivity
if ( null != m_xport ) {
warnIfNoTransport();
trySendChats();
- removeNotifications();
+ Utils.cancelNotification( this, (int)m_rowid );
m_xport.tickle( m_connType );
tryInvites();
}
@@ -1923,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()
{
if ( XWApp.BTSUPPORTED || XWApp.SMSSUPPORTED ) {
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
index 29414613c..7456721ad 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
@@ -311,6 +311,7 @@ public class GameUtils {
GameLock lock = new GameLock( rowid, true );
if ( lock.tryLock() ) {
tellDied( context, lock, informNow );
+ Utils.cancelNotification( context, (int)rowid );
DBUtils.deleteGame( context, lock );
lock.unlock();
} else {
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayService.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayService.java
index f2c33dc70..19dcf3e7c 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayService.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayService.java
@@ -69,7 +69,7 @@ public class RelayService extends Service {
String msg = Utils.format( this, R.string.notify_bodyf,
GameUtils.getName( this, rowid ) );
Utils.postNotification( this, intent, R.string.notify_title,
- msg, relayID.hashCode() );
+ msg, (int)rowid );
}
}
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java
index 0706ab878..30bed8477 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java
@@ -432,7 +432,8 @@ public class SMSService extends Service {
MultiService.OWNER_SMS );
intent.putExtra( MultiService.INVITER,
Utils.phoneToContact( this, phone, true ) );
- MultiService.postMissingDictNotification( this, intent, gameID );
+ MultiService.postMissingDictNotification( this, intent,
+ gameID );
}
break;
case DATA:
@@ -542,7 +543,7 @@ public class SMSService extends Service {
String owner = Utils.phoneToContact( this, phone, true );
String body = Utils.format( this, R.string.new_name_bodyf,
owner );
- postNotification( gameID, R.string.new_sms_title, body );
+ postNotification( gameID, R.string.new_sms_title, body, rowid );
ackInvite( phone, gameID );
}
@@ -607,18 +608,19 @@ public class SMSService extends Service {
if ( GameUtils.feedMessage( this, rowid, msg, addr,
sink ) ) {
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 = GamesList.makeGameIDIntent( this, gameID );
- Utils.postNotification( this, intent, title, body, gameID );
+ Utils.postNotification( this, intent, title, body, (int)rowid );
}
// Runs in separate thread
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/Utils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/Utils.java
index 288566417..5585407e9 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/Utils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/Utils.java
@@ -174,7 +174,8 @@ public class Utils {
}
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
http://stackoverflow.com/questions/10561419/scheduling-more-than-one-pendingintent-to-same-activity-using-alarmmanager
From 8250447eca79df8c4ef4c886a6ac5ff57f86402c Mon Sep 17 00:00:00 2001
From: Eric House
Date: Wed, 28 Nov 2012 20:41:08 -0800
Subject: [PATCH 075/146] launch game after successfully downloading dict it's
missing
---
.../org/eehouse/android/xw4/GamesList.java | 27 +++++++++++++------
1 file changed, 19 insertions(+), 8 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
index 43028718b..6a9c14879 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
@@ -83,7 +83,7 @@ public class GamesList extends XWListActivity
private GameListAdapter m_adapter;
private String m_missingDict;
private String m_missingDictName;
- private long m_missingDictRowId;
+ private long m_missingDictRowId = DBUtils.ROWID_NOTFOUND;
private String[] m_sameLangDicts;
private int m_missingDictLang;
private long m_rowid;
@@ -162,8 +162,7 @@ public class GamesList extends XWListActivity
m_missingDictRowId,
m_missingDictName,
dict );
- GameUtils.launchGame( GamesList.this,
- m_missingDictRowId );
+ launchGameIf();
}
};
dialog = new AlertDialog.Builder( this )
@@ -596,7 +595,10 @@ public class GamesList extends XWListActivity
{
post( new Runnable() {
public void run() {
- boolean madeGame = success ? makeNewNetGameIf() : false;
+ boolean madeGame = false;
+ if ( success ) {
+ madeGame = makeNewNetGameIf() || launchGameIf();
+ }
if ( ! madeGame ) {
int id = success ? R.string.download_done
: R.string.download_failed;
@@ -698,9 +700,8 @@ public class GamesList extends XWListActivity
{
String[][] missingNames = new String[1][];
int[] missingLang = new int[1];
- boolean hasDicts = GameUtils.gameDictsHere( this, rowid,
- missingNames,
- missingLang );
+ boolean hasDicts =
+ GameUtils.gameDictsHere( this, rowid, missingNames, missingLang );
if ( !hasDicts ) {
m_missingDictLang = missingLang[0];
if ( 0 < missingNames[0].length ) {
@@ -716,7 +717,7 @@ public class GamesList extends XWListActivity
} else {
String dict = DictLangCache.getHaveLang( this, m_missingDictLang)[0];
GameUtils.replaceDicts( this, m_missingDictRowId, null, dict );
- GameUtils.launchGame( this, m_missingDictRowId );
+ launchGameIf();
}
}
return hasDicts;
@@ -846,6 +847,16 @@ public class GamesList extends XWListActivity
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 );
From bffb231d1390ebdc14747a2cdc8bc4e5ff3ca561 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Wed, 28 Nov 2012 21:07:03 -0800
Subject: [PATCH 076/146] improve download-or-cancel messages
---
xwords4/android/XWords4/res/values/strings.xml | 15 ++++++++-------
.../src/org/eehouse/android/xw4/GamesList.java | 16 +++++++++++-----
2 files changed, 19 insertions(+), 12 deletions(-)
diff --git a/xwords4/android/XWords4/res/values/strings.xml b/xwords4/android/XWords4/res/values/strings.xml
index 514732fb1..d44207c89 100644
--- a/xwords4/android/XWords4/res/values/strings.xml
+++ b/xwords4/android/XWords4/res/values/strings.xml
@@ -1461,9 +1461,10 @@
downloading and not opening the game. This first message
takes wordlist name and language substituted in for %1$ and
%2$ -->
- Unable to open game \"%1$s\" because no
- %2$s wordlist found. (It may have been deleted, or stored on
- an external card that is no longer available.)
+ You need to download a replacement %2$s
+ wordlist before you can open game \"%1$s\". (The original may have
+ been deleted or stored on an external card that is no longer
+ available.)
diff --git a/xwords4/android/XWords4/res/values/common_rsrc.xml b/xwords4/android/XWords4/res/values/common_rsrc.xml
index 516e9aa13..860b43b11 100644
--- a/xwords4/android/XWords4/res/values/common_rsrc.xml
+++ b/xwords4/android/XWords4/res/values/common_rsrc.xml
@@ -104,6 +104,9 @@
eehouse.org
/and/
+ application/x-xwordsinvite
+
+
http://eehouse.org/and_wordlists
Update checks URL
http://eehouse.org/xw4/info.py
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
index aa80833e4..468229df6 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
@@ -24,12 +24,15 @@ import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
+import android.text.Html;
import java.io.File;
+import java.io.FileOutputStream;
import java.util.Arrays;
-import java.util.concurrent.locks.Lock;
import java.util.HashMap;
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;
@@ -539,11 +542,25 @@ public class GameUtils {
Intent intent = new Intent();
if ( choseEmail ) {
intent.setAction( Intent.ACTION_SEND );
- intent.setType( "message/rfc822");
String subject =
Utils.format( context, R.string.invite_subjectf, room );
intent.putExtra( Intent.EXTRA_SUBJECT, subject );
intent.putExtra( Intent.EXTRA_TEXT, Html.fromHtml(message) );
+
+ File tmpdir = DictUtils.getDownloadDir( context );
+ 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;
} else {
intent.setAction( Intent.ACTION_VIEW );
@@ -901,5 +918,29 @@ public class GameUtils {
}
}
+ private static File makeJsonFor( File dir, String room, String inviteID,
+ int lang, String dict, int nPlayers )
+ {
+ File result = null;
+ 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;
+ }
}
From ab0fb918eea802c270b80f2df985738447eab8f8 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Fri, 30 Nov 2012 06:21:18 -0800
Subject: [PATCH 079/146] open json attachment and from it create a new game.
Works, but there are enough problems with attachements I may turn them off.
---
.../src/org/eehouse/android/xw4/DBUtils.java | 2 +-
.../org/eehouse/android/xw4/GamesList.java | 2 +-
.../eehouse/android/xw4/NetLaunchInfo.java | 37 +++++++++++++++----
3 files changed, 31 insertions(+), 10 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
index 72b8338e4..edea22652 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
@@ -562,7 +562,7 @@ public class DBUtils {
public static long getRowIDForOpen( Context context, Uri data )
{
long rowid = ROWID_NOTFOUND;
- NetLaunchInfo nli = new NetLaunchInfo( data );
+ NetLaunchInfo nli = new NetLaunchInfo( context, data );
if ( null != nli && nli.isValid() ) {
rowid = getRowIDForOpen( context, nli );
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
index 0ee0a06ce..0b7155f09 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
@@ -800,7 +800,7 @@ public class GamesList extends XWListActivity
} else {
Uri data = intent.getData();
if ( null != data ) {
- nli = new NetLaunchInfo( data );
+ nli = new NetLaunchInfo( this, data );
}
}
if ( null != nli && nli.isValid() ) {
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetLaunchInfo.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetLaunchInfo.java
index 0fa720132..e2f79b4ed 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetLaunchInfo.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetLaunchInfo.java
@@ -20,11 +20,15 @@
package org.eehouse.android.xw4;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import java.net.URLEncoder;
+import java.io.InputStream;
+import org.json.JSONObject;
+import junit.framework.Assert;
public class NetLaunchInfo {
@@ -63,18 +67,35 @@ public class NetLaunchInfo {
m_valid = bundle.getBoolean( VALID );
}
- public NetLaunchInfo( Uri data )
+ public NetLaunchInfo( Context context, Uri data )
{
m_valid = false;
if ( null != data ) {
+ String scheme = data.getScheme();
try {
- 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 );
+ if ( "content".equals(scheme) ) {
+ Assert.assertNotNull( context );
+ ContentResolver resolver = context.getContentResolver();
+ InputStream is = resolver.openInputStream( data );
+ int len = is.available();
+ byte[] buf = new byte[len];
+ 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;
} catch ( Exception e ) {
DbgUtils.logf( "unable to parse \"%s\"", data.toString() );
From 95062fb967e7b93b1023b59a30f63ef00f4f3c76 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Fri, 30 Nov 2012 07:12:07 -0800
Subject: [PATCH 080/146] log missing dicts
---
.../XWords4/src/org/eehouse/android/xw4/GameUtils.java | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
index 468229df6..4c38cbcf7 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
@@ -25,6 +25,7 @@ import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.text.Html;
+import android.text.TextUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Arrays;
@@ -348,7 +349,8 @@ public class GameUtils {
String[] dictNames = gi.dictNames();
DictUtils.DictPairs pairs = DictUtils.openDicts( context, dictNames );
if ( pairs.anyMissing( dictNames ) ) {
- DbgUtils.logf( "loadMakeGame() failing: dict unavailable" );
+ DbgUtils.logf( "loadMakeGame() failing: dicts %s unavailable",
+ TextUtils.join( ",", dictNames ) );
} else {
gamePtr = XwJNI.initJNI();
From 32d7daf2b5af3138d0df0d13485fbf98bcf864f6 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Fri, 30 Nov 2012 07:13:00 -0800
Subject: [PATCH 081/146] warn about duplicate games not just when there's
exactly one, and include the most recent create time in the warning.
---
.../android/XWords4/res/values/strings.xml | 4 +--
.../src/org/eehouse/android/xw4/DBUtils.java | 26 ++++++++++++-------
.../org/eehouse/android/xw4/GamesList.java | 22 +++++++++-------
3 files changed, 30 insertions(+), 22 deletions(-)
diff --git a/xwords4/android/XWords4/res/values/strings.xml b/xwords4/android/XWords4/res/values/strings.xml
index d44207c89..000b4f633 100644
--- a/xwords4/android/XWords4/res/values/strings.xml
+++ b/xwords4/android/XWords4/res/values/strings.xml
@@ -1552,8 +1552,8 @@
the same room name over and over so they'll get this warning
and it's harmless to ignore it. -->
You already have a game that seems
- to have been created from the same invitation. Are you sure you
- want to open another?
+ to have been created (on %1$s) from the same invitation. Are you
+ sure you want to create another?
FYI...
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
index edea22652..bc96d8db4 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
@@ -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 );
synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
- String[] columns = { ROW_ID };
+ String[] columns = { DBHelper.CREATE_TIME };
String selection =
String.format( "%s='%s' AND %s='%s' AND %s=%d AND %s=%d",
DBHelper.ROOMNAME, nli.room,
@@ -549,9 +552,12 @@ public class DBUtils {
DBHelper.DICTLANG, nli.lang,
DBHelper.NUM_PLAYERS, nli.nPlayersT );
Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
- selection, null, null, null, null );
- if ( 1 == cursor.getCount() && cursor.moveToFirst() ) {
- result = cursor.getLong( cursor.getColumnIndex(ROW_ID) );
+ selection, null, null, null,
+ DBHelper.CREATE_TIME + " DESC" ); // order by
+ while ( cursor.moveToNext() ) {
+ int indx = cursor.getColumnIndex( DBHelper.CREATE_TIME );
+ result = new Date( cursor.getLong( indx ) );
+ break;
}
cursor.close();
db.close();
@@ -559,14 +565,14 @@ public class DBUtils {
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( context, data );
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 )
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
index 0b7155f09..2fb7f724f 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
@@ -20,30 +20,31 @@
package org.eehouse.android.xw4;
-import android.app.ListActivity;
-import android.app.Dialog;
import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.ListActivity;
import android.app.PendingIntent;
import android.content.Context;
-import android.content.Intent;
import android.content.DialogInterface;
+import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
+import android.preference.PreferenceManager;
+import android.view.ContextMenu.ContextMenuInfo;
import android.view.ContextMenu;
import android.view.Menu;
+import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
-import android.view.ContextMenu.ContextMenuInfo;
import android.widget.AdapterView;
+import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
-import android.widget.Button;
-import android.view.MenuInflater;
import java.io.File;
-import android.preference.PreferenceManager;
+import java.util.Date;
// import android.telephony.PhoneStateListener;
// import android.telephony.TelephonyManager;
import junit.framework.Assert;
@@ -779,14 +780,15 @@ public class GamesList extends XWListActivity
private void startNewNetGame( NetLaunchInfo nli )
{
- long rowid = DBUtils.getRowIDForOpen( this, nli );
+ Date create = DBUtils.getMostRecentCreate( this, nli );
- if ( DBUtils.ROWID_NOTFOUND == rowid ) {
+ if ( null == create ) {
if ( checkWarnNoDict( nli ) ) {
makeNewNetGame( nli );
}
} else {
- String msg = getString( R.string.dup_game_queryf, nli.room );
+ String msg = getString( R.string.dup_game_queryf,
+ create.toString() );
m_netLaunchInfo = nli;
showConfirmThen( msg, NEW_NET_GAME_ACTION );
}
From 8b5ec28120111a4ebcf5fbd0995c6ddc0eee88f4 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Fri, 30 Nov 2012 07:22:16 -0800
Subject: [PATCH 082/146] SMS play logs too much: remove non-error logging.
---
.../XWords4/src/org/eehouse/android/xw4/SMSService.java | 7 -------
1 file changed, 7 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java
index 30bed8477..6734e1220 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java
@@ -388,7 +388,6 @@ public class SMSService extends Service {
int count = (msg.length() + (MAX_LEN_TEXT-1)) / MAX_LEN_TEXT;
String[] result = new String[count];
int msgID = ++s_nSent % 0x000000FF;
- DbgUtils.logf( "preparing %d packets for msgid %x", count, msgID );
int start = 0;
int end = 0;
@@ -400,7 +399,6 @@ public class SMSService extends Service {
end += len;
result[ii] = String.format( "0:%X:%X:%X:%s", msgID, ii, count,
msg.substring( start, end ) );
- DbgUtils.logf( "fragment[%d]: %s", ii, result[ii] );
start = end;
}
return result;
@@ -505,7 +503,6 @@ public class SMSService extends Service {
private void disAssemble( String senderPhone, String fullMsg )
{
- DbgUtils.logf( "disAssemble()" );
byte[] data = XwJNI.base64Decode( fullMsg );
DataInputStream dis =
new DataInputStream( new ByteArrayInputStream(data) );
@@ -564,8 +561,6 @@ public class SMSService extends Service {
for ( String fragment : fragments ) {
String asPublic = toPublicFmt( fragment );
mgr.sendTextMessage( phone, null, asPublic, sent, delivery );
- DbgUtils.logf( "Message \"%s\" of %d bytes sent to %s.",
- asPublic, asPublic.length(), phone );
}
if ( s_showToasts ) {
DbgUtils.showf( this, "sent %dth msg", s_nSent );
@@ -707,7 +702,6 @@ public class SMSService extends Service {
public int transportSend( byte[] buf, final CommsAddrRec addr, int gameID )
{
int nSent = -1;
- DbgUtils.logf( "SMSMsgSink.transportSend()" );
if ( null != addr ) {
nSent = sendPacket( addr.sms_phone, gameID, buf );
} else {
@@ -750,7 +744,6 @@ public class SMSService extends Service {
public boolean isComplete()
{
boolean complete = m_msgs.length == m_haveCount;
- DbgUtils.logf( "isComplete(msg %d)=>%b", m_msgID, complete );
return complete;
}
From 74fec9d3d3041531baae7898ead8fe80bbf9ef70 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Fri, 30 Nov 2012 07:50:10 -0800
Subject: [PATCH 083/146] disable attachments as part of invitations -- for
now.
---
xwords4/android/XWords4/AndroidManifest.xml | 16 ++++----
.../org/eehouse/android/xw4/GameUtils.java | 37 ++++++++++---------
.../src/org/eehouse/android/xw4/XWApp.java | 1 +
3 files changed, 29 insertions(+), 25 deletions(-)
diff --git a/xwords4/android/XWords4/AndroidManifest.xml b/xwords4/android/XWords4/AndroidManifest.xml
index fd9edb100..640303a36 100644
--- a/xwords4/android/XWords4/AndroidManifest.xml
+++ b/xwords4/android/XWords4/AndroidManifest.xml
@@ -134,14 +134,14 @@
/>
-
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
index 4c38cbcf7..19317bf77 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
@@ -549,7 +549,8 @@ public class GameUtils {
intent.putExtra( Intent.EXTRA_SUBJECT, subject );
intent.putExtra( Intent.EXTRA_TEXT, Html.fromHtml(message) );
- File tmpdir = DictUtils.getDownloadDir( context );
+ File tmpdir = XWApp.ATTACH_SUPPORTED ?
+ DictUtils.getDownloadDir( context ) : null;
if ( null == tmpdir ) { // no attachment
intent.setType( "message/rfc822");
} else {
@@ -924,23 +925,25 @@ public class GameUtils {
int lang, String dict, int nPlayers )
{
File result = null;
- 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();
+ 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 );
+ 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;
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java
index 6c1623967..0525faf7d 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java
@@ -32,6 +32,7 @@ public class XWApp extends Application {
public static final boolean BTSUPPORTED = false;
public static final boolean SMSSUPPORTED = true;
public static final boolean GCMSUPPORTED = true;
+ public static final boolean ATTACH_SUPPORTED = false;
public static final boolean DEBUG = false;
public static final String SMS_PUBLIC_HEADER = "-XW4";
From 13b7877a80f252bc1a1de9c0b8c042c8d5643e82 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Fri, 30 Nov 2012 08:08:45 -0800
Subject: [PATCH 084/146] put name of file being downloaded in progress dialog
---
xwords4/android/XWords4/res/values/strings.xml | 4 +---
.../src/org/eehouse/android/xw4/DictImportActivity.java | 9 +++++----
2 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/xwords4/android/XWords4/res/values/strings.xml b/xwords4/android/XWords4/res/values/strings.xml
index 000b4f633..956715178 100644
--- a/xwords4/android/XWords4/res/values/strings.xml
+++ b/xwords4/android/XWords4/res/values/strings.xml
@@ -1427,9 +1427,7 @@
Guest wordlists; Host wins.
-
- Downloading Crosswords
- wordlist %s...
+ Downloading %s...
+ Rematch
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
index dcbd08151..7c01d39f2 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
@@ -75,7 +75,7 @@ public class BoardActivity extends XWActivity
private static final int PICK_TILE_REQUESTTRAY_BLK = DLG_OKONLY + 11;
private static final int DLG_USEDICT = DLG_OKONLY + 12;
private static final int DLG_GETDICT = DLG_OKONLY + 13;
-
+ private static final int GAME_OVER = DLG_OKONLY + 14;
private static final int CHAT_REQUEST = 1;
private static final int BT_INVITE_RESULT = 2;
@@ -235,6 +235,7 @@ public class BoardActivity extends XWActivity
case DLG_OKONLY:
case DLG_BADWORDS:
case DLG_RETRY:
+ case GAME_OVER:
ab = new AlertDialog.Builder( this )
.setTitle( m_dlgTitle )
.setMessage( m_dlgBytes )
@@ -247,6 +248,15 @@ public class BoardActivity extends XWActivity
}
};
ab.setNegativeButton( R.string.button_retry, lstnr );
+ } else if ( GAME_OVER == id ) {
+ lstnr = new DialogInterface.OnClickListener() {
+ public void onClick( DialogInterface dlg,
+ int whichButton ) {
+ Utils.notImpl( BoardActivity.this );
+ finish();
+ }
+ };
+ ab.setNegativeButton( R.string.button_rematch, lstnr );
}
dialog = ab.create();
Utils.setRemoveOnDismiss( this, dialog, id );
@@ -1700,6 +1710,11 @@ public class BoardActivity extends XWActivity
launchLookup( wordsToArray((String)msg.obj),
m_gi.dictLang );
break;
+ case JNIThread.GAME_OVER:
+ m_dlgBytes = (String)msg.obj;
+ m_dlgTitle = msg.arg1;
+ showDialog( GAME_OVER );
+ break;
}
}
};
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java
index 3cc42187c..71577dc6a 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java
@@ -94,6 +94,7 @@ public class JNIThread extends Thread {
public static final int QUERY_ENDGAME = 4;
public static final int TOOLBAR_STATES = 5;
public static final int GOT_WORDS = 6;
+ public static final int GAME_OVER = 7;
public class GameStateInfo implements Cloneable {
public int visTileCount;
@@ -528,8 +529,10 @@ public class JNIThread extends Thread {
((Boolean)args[0]).booleanValue();
int titleID = auto? R.string.summary_gameover
: R.string.finalscores_title;
- sendForDialog( titleID,
- XwJNI.server_writeFinalScores( m_jniGamePtr ) );
+
+ String text = XwJNI.server_writeFinalScores( m_jniGamePtr );
+ Message.obtain( m_handler, GAME_OVER, titleID, 0, text )
+ .sendToTarget();
}
break;
From da9c7a1afd2a39c05e723932a5c1aacc1f0a7090 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Sun, 2 Dec 2012 21:39:33 -0800
Subject: [PATCH 099/146] comment out unused column
---
.../android/XWords4/src/org/eehouse/android/xw4/DBHelper.java | 4 ++--
.../android/XWords4/src/org/eehouse/android/xw4/DBUtils.java | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java
index b44021f29..cf6a4d6bd 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java
@@ -60,7 +60,7 @@ public class DBHelper extends SQLiteOpenHelper {
public static final String INVITEID = "INVITEID";
public static final String RELAYID = "RELAYID";
public static final String SEED = "SEED";
- public static final String SMSPHONE = "SMSPHONE";
+ public static final String SMSPHONE = "SMSPHONE"; // unused -- so far
public static final String LASTMOVE = "LASTMOVE";
public static final String GROUPID = "GROUPID";
@@ -100,7 +100,7 @@ public class DBHelper extends SQLiteOpenHelper {
,SEED, "INTEGER"
,DICTLANG, "INTEGER"
,DICTLIST, "TEXT"
- ,SMSPHONE, "TEXT"
+ ,SMSPHONE, "TEXT" // unused
,SCORES, "TEXT"
,CHAT_HISTORY, "TEXT"
,GAMEID, "INTEGER"
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
index f3504932f..303b09af9 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
@@ -129,7 +129,7 @@ public class DBUtils {
DBHelper.TURN, DBHelper.GIFLAGS,
DBHelper.CONTYPE, DBHelper.SERVERROLE,
DBHelper.ROOMNAME, DBHelper.RELAYID,
- DBHelper.SMSPHONE, DBHelper.SEED,
+ /*DBHelper.SMSPHONE,*/ DBHelper.SEED,
DBHelper.DICTLANG, DBHelper.GAMEID,
DBHelper.SCORES, DBHelper.HASMSGS,
DBHelper.LASTPLAY_TIME, DBHelper.REMOTEDEVS,
From a640f9d97b816454ccb7195deb8cbfa17ecfc419 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Mon, 3 Dec 2012 06:51:50 -0800
Subject: [PATCH 100/146] up version number and string
---
xwords4/android/XWords4/AndroidManifest.xml | 2 +-
xwords4/android/XWords4/res/raw/changes | 15 ++++++---------
xwords4/android/XWords4/res/values/app_name.xml | 2 +-
3 files changed, 8 insertions(+), 11 deletions(-)
diff --git a/xwords4/android/XWords4/AndroidManifest.xml b/xwords4/android/XWords4/AndroidManifest.xml
index 640303a36..9524eab68 100644
--- a/xwords4/android/XWords4/AndroidManifest.xml
+++ b/xwords4/android/XWords4/AndroidManifest.xml
@@ -22,7 +22,7 @@
to come from a domain that you own or have control over. -->
diff --git a/xwords4/android/XWords4/res/raw/changes b/xwords4/android/XWords4/res/raw/changes
index 20c716fa5..c1165a0bd 100644
--- a/xwords4/android/XWords4/res/raw/changes
+++ b/xwords4/android/XWords4/res/raw/changes
@@ -5,17 +5,14 @@
-Crosswords 4.4 beta 56 release
-New with this release
- - Improve invitations: no more redirection through a website, and
- confirm before creating duplicate games
- - (For sideloading users only) No more browser involvement in
- updates: app can launch the installer directly to update
- itself
- - Remove notifications when their games are deleted
+Crosswords 4.4 beta 57 release
+
+New with this release
+
-Next up
+Next up
+
- One more idea for improving invitations
- Allow grouping of games in collapsible user-defined categores: "Games with
Kati", "Finished games", etc.
diff --git a/xwords4/android/XWords4/res/values/app_name.xml b/xwords4/android/XWords4/res/values/app_name.xml
index 844bb12a6..095652a34 100644
--- a/xwords4/android/XWords4/res/values/app_name.xml
+++ b/xwords4/android/XWords4/res/values/app_name.xml
@@ -1,5 +1,5 @@
- 4.4 beta 56
+ 4.4 beta 57
From ad606cdec073e6898584f115590d5f6abe7084cb Mon Sep 17 00:00:00 2001
From: Eric House
Date: Mon, 3 Dec 2012 06:53:15 -0800
Subject: [PATCH 101/146] trying to figure out why games list is occasionally
redrawing itself all the time: add logging that activated only when XWApp's
DEBUG flag is set, and turn that flag on. The latter change should be
reversed before the next release.
---
.../eehouse/android/xw4/ExpiringDelegate.java | 8 +++++++
.../eehouse/android/xw4/GameListAdapter.java | 23 ++++++++++++++-----
.../src/org/eehouse/android/xw4/XWApp.java | 2 +-
3 files changed, 26 insertions(+), 7 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/ExpiringDelegate.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/ExpiringDelegate.java
index 7d1b13968..13083266d 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/ExpiringDelegate.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/ExpiringDelegate.java
@@ -194,12 +194,20 @@ public class ExpiringDelegate {
if ( null == m_runnable ) {
m_runnable = new Runnable() {
public void run() {
+ if ( XWApp.DEBUG ) {
+ DbgUtils.logf( "ExpiringDelegate: timer fired"
+ + " for %H", this );
+ }
if ( m_active ) {
figurePct();
if ( m_haveTurnLocal ) {
m_back = null;
setBackground();
}
+ if ( XWApp.DEBUG ) {
+ DbgUtils.logf( "ExpiringDelegate: invalidating"
+ + " view %H", m_view );
+ }
m_view.invalidate();
}
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java
index c234cb09a..ec28a52f0 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java
@@ -1,7 +1,7 @@
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
- * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
- * rights reserved.
+ * Copyright 2009-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
@@ -249,7 +249,9 @@ public class GameListAdapter extends XWListAdapter {
ViewInfo vi = new ViewInfo( layout, m_rowid, expanded,
summary.lastMoveTime, haveATurn,
haveALocalTurn );
-
+ if ( XWApp.DEBUG ) {
+ DbgUtils.logf( "created new view for rowid %d", m_rowid );
+ }
synchronized( m_viewsCache ) {
m_viewsCache.put( m_rowid, vi );
}
@@ -329,7 +331,7 @@ public class GameListAdapter extends XWListAdapter {
}
}
- public void setField( String field )
+ public void setField( String fieldName )
{
int[] ids = {
R.string.game_summary_field_empty
@@ -339,12 +341,21 @@ public class GameListAdapter extends XWListAdapter {
};
int result = -1;
for ( int id : ids ) {
- if ( m_context.getString( id ).equals( field ) ) {
+ if ( m_context.getString( id ).equals( fieldName ) ) {
result = id;
break;
}
}
- if ( m_fieldID != result ) {
+ if ( -1 == result ) {
+ if ( XWApp.DEBUG ) {
+ DbgUtils.logf( "GameListAdapter.setField(): unable to match"
+ + " fieldName %s", fieldName );
+ }
+ } else if ( m_fieldID != result ) {
+ if ( XWApp.DEBUG ) {
+ DbgUtils.logf( "setField: clearing views cache for change"
+ + " from %d to %d", m_fieldID, result );
+ }
m_viewsCache.clear();
m_fieldID = result;
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java
index 0525faf7d..06bec14f1 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java
@@ -33,7 +33,7 @@ public class XWApp extends Application {
public static final boolean SMSSUPPORTED = true;
public static final boolean GCMSUPPORTED = true;
public static final boolean ATTACH_SUPPORTED = false;
- public static final boolean DEBUG = false;
+ public static final boolean DEBUG = true; // DON'T SHIP THIS WAY
public static final String SMS_PUBLIC_HEADER = "-XW4";
From c041792f837f87d419632bd585241725fb04c8f6 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Mon, 3 Dec 2012 08:03:00 -0800
Subject: [PATCH 102/146] move methods toward better encapsualtion (no behavior
change)
---
.../eehouse/android/xw4/BTInviteActivity.java | 8 ++++++++
.../org/eehouse/android/xw4/BoardActivity.java | 8 ++++----
.../src/org/eehouse/android/xw4/GameUtils.java | 16 ----------------
.../org/eehouse/android/xw4/InviteActivity.java | 2 +-
.../org/eehouse/android/xw4/NewGameActivity.java | 4 ++--
.../eehouse/android/xw4/SMSInviteActivity.java | 10 +++++++++-
6 files changed, 24 insertions(+), 24 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BTInviteActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BTInviteActivity.java
index c6a3297d3..fcfcbd51a 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BTInviteActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BTInviteActivity.java
@@ -45,6 +45,14 @@ public class BTInviteActivity extends InviteActivity
private boolean m_firstScan;
private int m_checkCount;
+ public static void launchForResult( Activity activity, int nMissing,
+ int requestCode )
+ {
+ Intent intent = new Intent( activity, BTInviteActivity.class );
+ intent.putExtra( INTENT_KEY_NMISSING, nMissing );
+ activity.startActivityForResult( intent, requestCode );
+ }
+
@Override
protected void onCreate( Bundle savedInstanceState )
{
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
index 7c01d39f2..64d1c775e 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
@@ -847,12 +847,12 @@ public class BoardActivity extends XWActivity
doSyncMenuitem();
break;
case BT_PICK_ACTION:
- GameUtils.launchBTInviter( this, m_nMissingPlayers,
- BT_INVITE_RESULT );
+ BTInviteActivity.launchForResult( this, m_nMissingPlayers,
+ BT_INVITE_RESULT );
break;
case SMS_PICK_ACTION:
- GameUtils.launchSMSInviter( this, m_nMissingPlayers,
- SMS_INVITE_RESULT );
+ SMSInviteActivity.launchForResult( this, m_nMissingPlayers,
+ SMS_INVITE_RESULT );
break;
case SMS_CONFIG_ACTION:
Utils.launchSettings( this );
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
index 19317bf77..9a291d1b8 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
@@ -508,22 +508,6 @@ public class GameUtils {
nPlayersH, null, gameID, isHost );
}
- public static void launchBTInviter( Activity activity, int nMissing,
- int requestCode )
- {
- Intent intent = new Intent( activity, BTInviteActivity.class );
- intent.putExtra( BTInviteActivity.INTENT_KEY_NMISSING, nMissing );
- activity.startActivityForResult( intent, requestCode );
- }
-
- public static void launchSMSInviter( Activity activity, int nMissing,
- int requestCode )
- {
- Intent intent = new Intent( activity, SMSInviteActivity.class );
- intent.putExtra( SMSInviteActivity.INTENT_KEY_NMISSING, nMissing );
- activity.startActivityForResult( intent, requestCode );
- }
-
public static void launchInviteActivity( Context context,
boolean choseEmail,
String room, String inviteID,
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/InviteActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/InviteActivity.java
index 1a5c803f0..41dd2ae7c 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/InviteActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/InviteActivity.java
@@ -43,7 +43,7 @@ abstract class InviteActivity extends XWListActivity
implements View.OnClickListener {
public static final String DEVS = "DEVS";
- public static final String INTENT_KEY_NMISSING = "NMISSING";
+ protected static final String INTENT_KEY_NMISSING = "NMISSING";
protected int m_nMissing;
protected Button m_okButton;
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NewGameActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NewGameActivity.java
index 039aaa23d..85bbccd63 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NewGameActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NewGameActivity.java
@@ -357,7 +357,7 @@ public class NewGameActivity extends XWActivity {
intent.putExtra( GameUtils.INTENT_FORRESULT_ROWID, true );
startActivityForResult( intent, CONFIG_FOR_BT );
} else {
- GameUtils.launchBTInviter( this, 1, INVITE_FOR_BT );
+ BTInviteActivity.launchForResult( this, 1, INVITE_FOR_BT );
}
}
@@ -378,7 +378,7 @@ public class NewGameActivity extends XWActivity {
intent.putExtra( GameUtils.INTENT_FORRESULT_ROWID, true );
startActivityForResult( intent, CONFIG_FOR_SMS );
} else {
- GameUtils.launchSMSInviter( this, 1, INVITE_FOR_SMS );
+ SMSInviteActivity.launchForResult( this, 1, INVITE_FOR_SMS );
}
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSInviteActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSInviteActivity.java
index 60a7da3dd..aa955374b 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSInviteActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSInviteActivity.java
@@ -32,9 +32,9 @@ import android.os.Bundle;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds;
import android.provider.ContactsContract;
-import android.text.method.DialerKeyListener;
import android.text.Editable;
import android.text.TextWatcher;
+import android.text.method.DialerKeyListener;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
@@ -64,6 +64,14 @@ public class SMSInviteActivity extends InviteActivity {
private String m_pendingNumber;
private boolean m_immobileConfirmed;
+ public static void launchForResult( Activity activity, int nMissing,
+ int requestCode )
+ {
+ Intent intent = new Intent( activity, SMSInviteActivity.class );
+ intent.putExtra( INTENT_KEY_NMISSING, nMissing );
+ activity.startActivityForResult( intent, requestCode );
+ }
+
@Override
protected void onCreate( Bundle savedInstanceState )
{
From 2c71c8425fa5e2addda9b8ad4be5392413c92a4c Mon Sep 17 00:00:00 2001
From: Eric House
Date: Mon, 3 Dec 2012 08:30:29 -0800
Subject: [PATCH 103/146] pass the rematch request off to GamesList where it
can create new games without interference from locked current game. Handle
standalone case by cloning and launching: easy. Networked games will be
harder.
---
.../eehouse/android/xw4/BoardActivity.java | 10 +++++--
.../org/eehouse/android/xw4/GamesList.java | 27 +++++++++++++++++++
2 files changed, 35 insertions(+), 2 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
index 64d1c775e..9998ba315 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
@@ -252,8 +252,7 @@ public class BoardActivity extends XWActivity
lstnr = new DialogInterface.OnClickListener() {
public void onClick( DialogInterface dlg,
int whichButton ) {
- Utils.notImpl( BoardActivity.this );
- finish();
+ doRematch();
}
};
ab.setNegativeButton( R.string.button_rematch, lstnr );
@@ -2106,4 +2105,11 @@ public class BoardActivity extends XWActivity
m_passwdEdit = (EditText)m_passwdLyt.findViewById( R.id.edit );
}
+ private void doRematch()
+ {
+ Intent intent = GamesList.makeRematchIntent( this, m_gi, m_rowid );
+ startActivity( intent );
+ finish();
+ }
+
} // class BoardActivity
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
index 2fb7f724f..4129c1cbf 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
@@ -68,6 +68,7 @@ public class GamesList extends XWListActivity
private static final String RELAYIDS_EXTRA = "relayids";
private static final String GAMEID_EXTRA = "gameid";
+ private static final String REMATCH_ROWID_EXTRA = "rowid";
private static final int NEW_NET_GAME_ACTION = 1;
private static final int RESET_GAME_ACTION = 2;
@@ -291,6 +292,7 @@ public class GamesList extends XWListActivity
startFirstHasDict( intent );
startNewNetGame( intent );
startHasGameID( intent );
+ startHasRowID( intent );
askDefaultNameIf();
} // onCreate
@@ -305,6 +307,7 @@ public class GamesList extends XWListActivity
startFirstHasDict( intent );
startNewNetGame( intent );
startHasGameID( intent );
+ startHasRowID( intent );
}
@Override
@@ -826,6 +829,16 @@ public class GamesList extends XWListActivity
}
}
+ private void startHasRowID( Intent intent )
+ {
+ long rowid = intent.getLongExtra( REMATCH_ROWID_EXTRA, -1 );
+ if ( -1 != rowid ) {
+ // this will juggle if the preference is set
+ long newid = GameUtils.dupeGame( this, rowid );
+ GameUtils.launchGame( this, newid );
+ }
+ }
+
private void askDefaultNameIf()
{
if ( null == CommonPrefs.getDefaultPlayerName( this, 0, false ) ) {
@@ -900,6 +913,20 @@ public class GamesList extends XWListActivity
return intent;
}
+ public static Intent makeRematchIntent( Context context, CurGameInfo gi,
+ long rowid )
+ {
+ Intent intent = makeSelfIntent( context );
+
+ if ( CurGameInfo.DeviceRole.SERVER_STANDALONE == gi.serverRole ) {
+ intent.putExtra( REMATCH_ROWID_EXTRA, rowid );
+ } else {
+ Utils.notImpl( context );
+ }
+
+ return intent;
+ }
+
public static void openGame( Context context, Uri data )
{
Intent intent = makeSelfIntent( context );
From 922f4a22f4a4b05fdba35c2644f1e745a2f58498 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Mon, 3 Dec 2012 23:07:14 -0800
Subject: [PATCH 104/146] remove unneeded variable
---
.../src/org/eehouse/android/xw4/GameListAdapter.java | 5 ++++-
.../XWords4/src/org/eehouse/android/xw4/GamesList.java | 7 ++-----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java
index ec28a52f0..bcdfbefe3 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java
@@ -331,8 +331,9 @@ public class GameListAdapter extends XWListAdapter {
}
}
- public void setField( String fieldName )
+ public boolean setField( String fieldName )
{
+ boolean changed = false;
int[] ids = {
R.string.game_summary_field_empty
,R.string.game_summary_field_language
@@ -358,7 +359,9 @@ public class GameListAdapter extends XWListAdapter {
}
m_viewsCache.clear();
m_fieldID = result;
+ changed = true;
}
+ return changed;
}
}
\ No newline at end of file
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
index 4129c1cbf..fbed5b9d7 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
@@ -90,7 +90,6 @@ public class GamesList extends XWListActivity
private String[] m_sameLangDicts;
private int m_missingDictLang;
private long m_rowid;
- private String m_nameField;
private NetLaunchInfo m_netLaunchInfo;
// private String m_smsPhone;
@@ -851,10 +850,8 @@ public class GamesList extends XWListActivity
private void updateField()
{
String newField = CommonPrefs.getSummaryField( this );
- if ( ! newField.equals( m_nameField ) ) {
- m_nameField = newField;
- m_adapter.setField( newField );
- onContentChanged();
+ if ( m_adapter.setField( newField ) ) {
+ onContentChanged();
}
}
From ac8c229e75c22fa322273ed50c6891a889866e8e Mon Sep 17 00:00:00 2001
From: Eric House
Date: Mon, 3 Dec 2012 23:10:31 -0800
Subject: [PATCH 105/146] Fix attachments, at least for the one phone I've
tested on. Requires K-9 mail (Gmail doesn't allow opening attachments).
Trick was to drop the file extension, since if present that seems to come
ahead of mime type for filtering.
---
xwords4/android/XWords4/AndroidManifest.xml | 14 ++++++--------
.../src/org/eehouse/android/xw4/GameUtils.java | 2 +-
.../XWords4/src/org/eehouse/android/xw4/XWApp.java | 2 +-
3 files changed, 8 insertions(+), 10 deletions(-)
diff --git a/xwords4/android/XWords4/AndroidManifest.xml b/xwords4/android/XWords4/AndroidManifest.xml
index 9524eab68..ba77b8886 100644
--- a/xwords4/android/XWords4/AndroidManifest.xml
+++ b/xwords4/android/XWords4/AndroidManifest.xml
@@ -134,14 +134,12 @@
/>
-
-
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
index 9a291d1b8..52b274823 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
@@ -920,7 +920,7 @@ public class GameUtils {
byte[] data = json.toString().getBytes();
File file = new File( dir,
- String.format("invite_%s.json", room ) );
+ String.format("invite_%s", room ) );
FileOutputStream fos = new FileOutputStream( file );
fos.write( data, 0, data.length );
fos.close();
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java
index 06bec14f1..57927412b 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java
@@ -32,7 +32,7 @@ public class XWApp extends Application {
public static final boolean BTSUPPORTED = false;
public static final boolean SMSSUPPORTED = true;
public static final boolean GCMSUPPORTED = true;
- public static final boolean ATTACH_SUPPORTED = false;
+ public static final boolean ATTACH_SUPPORTED = true;
public static final boolean DEBUG = true; // DON'T SHIP THIS WAY
public static final String SMS_PUBLIC_HEADER = "-XW4";
From a035ef5623af299019c3ba9c5e6e40a423a8f52e Mon Sep 17 00:00:00 2001
From: Eric House
Date: Wed, 5 Dec 2012 06:52:10 -0800
Subject: [PATCH 106/146] attachment can come in as file or content scheme
---
.../XWords4/src/org/eehouse/android/xw4/NetLaunchInfo.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetLaunchInfo.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetLaunchInfo.java
index e2f79b4ed..878316cf1 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetLaunchInfo.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetLaunchInfo.java
@@ -73,7 +73,7 @@ public class NetLaunchInfo {
if ( null != data ) {
String scheme = data.getScheme();
try {
- if ( "content".equals(scheme) ) {
+ if ( "content".equals(scheme) || "file".equals(scheme) ) {
Assert.assertNotNull( context );
ContentResolver resolver = context.getContentResolver();
InputStream is = resolver.openInputStream( data );
From af853098f2bd8f634673c08389d63f7a4277818b Mon Sep 17 00:00:00 2001
From: Eric House
Date: Wed, 5 Dec 2012 07:32:11 -0800
Subject: [PATCH 107/146] use preferred SDK-8 API to look for downloads
directory, and wrap it in an interface loaded only when SDK>=8 to avoid
load-time crash on older devices.
---
xwords4/android/XWords4/AndroidManifest.xml | 2 +-
xwords4/android/XWords4/project.properties | 2 +-
.../org/eehouse/android/xw4/DictUtils.java | 45 ++++++++++++++++++-
3 files changed, 45 insertions(+), 4 deletions(-)
diff --git a/xwords4/android/XWords4/AndroidManifest.xml b/xwords4/android/XWords4/AndroidManifest.xml
index ba77b8886..1b634d862 100644
--- a/xwords4/android/XWords4/AndroidManifest.xml
+++ b/xwords4/android/XWords4/AndroidManifest.xml
@@ -26,7 +26,7 @@
android:versionName="@string/app_version"
>
-
+
diff --git a/xwords4/android/XWords4/project.properties b/xwords4/android/XWords4/project.properties
index 797fb4fc3..c1fd41ab1 100644
--- a/xwords4/android/XWords4/project.properties
+++ b/xwords4/android/XWords4/project.properties
@@ -10,4 +10,4 @@
# Indicates whether an apk should be generated for each density.
split.density=false
# Project target.
-target=android-7
+target=android-8
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java
index 126410cfd..6adcc5e6e 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java
@@ -47,6 +47,20 @@ import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole;
public class DictUtils {
+ // Standard hack for using APIs from an SDK in code to ship on
+ // older devices that don't support it: prevent class loader from
+ // seeing something it'll barf on by loading it manually
+ private static interface SafeDirGetter {
+ public File getDownloadDir();
+ }
+ private static SafeDirGetter s_dirGetter = null;
+ static {
+ int sdkVersion = Integer.valueOf( android.os.Build.VERSION.SDK );
+ if ( 8 <= sdkVersion ) {
+ s_dirGetter = new DirGetter();
+ }
+ }
+
// keep in sync with loc_names string-array
public enum DictLoc { UNKNOWN, BUILT_IN, INTERNAL, EXTERNAL, DOWNLOAD };
public static final String INVITED = "invited";
@@ -566,10 +580,21 @@ public class DictUtils {
return null != getDownloadDir( context );
}
+ // The approved way to get this is to call Environment.
+ // getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
+ // but at least on my Samsung Galaxy Blaze 4G it returns a
+ // directory that does not exist! (FU, Samsung...) So in that
+ // case fall back to using getExternalStorageDirectory and
+ // appending "download"
public static File getDownloadDir( Context context )
{
File result = null;
- if ( haveWriteableSD() ) {
+ if ( null != s_dirGetter ) {
+ result = s_dirGetter.getDownloadDir();
+ }
+ if ( null != result ) {
+ // we're done
+ } else if ( haveWriteableSD() ) {
File file = null;
String myPath = XWPrefs.getMyDownloadDir( context );
if ( null != myPath && 0 < myPath.length() ) {
@@ -577,7 +602,11 @@ public class DictUtils {
} else {
file = Environment.getExternalStorageDirectory();
if ( null != file ) {
- file = new File( file, "download/" );
+ File child = new File( file, "download/" );
+ if ( child.exists() && child.isDirectory()
+ && child.canWrite() ) {
+ file = child;
+ }
}
}
if ( null != file && file.exists() && file.isDirectory() ) {
@@ -596,4 +625,16 @@ public class DictUtils {
}
return result;
}
+
+ private static class DirGetter implements SafeDirGetter {
+ public File getDownloadDir()
+ {
+ File path = Environment.
+ getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
+ if ( null != path && !path.canWrite() ) {
+ path = null;
+ }
+ return path;
+ }
+ }
}
From 6789a64b68060bebe230334a80c0b6864225d4cf Mon Sep 17 00:00:00 2001
From: Eric House
Date: Wed, 5 Dec 2012 08:14:55 -0800
Subject: [PATCH 108/146] reduce redundant code (hopefully without adding too
much confusion)
---
.../org/eehouse/android/xw4/DictUtils.java | 63 ++++++++++---------
1 file changed, 34 insertions(+), 29 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java
index 6adcc5e6e..05fff08d0 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java
@@ -580,37 +580,45 @@ public class DictUtils {
return null != getDownloadDir( context );
}
- // The approved way to get this is to call Environment.
- // getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
- // but at least on my Samsung Galaxy Blaze 4G it returns a
- // directory that does not exist! (FU, Samsung...) So in that
- // case fall back to using getExternalStorageDirectory and
- // appending "download"
+ // Loop through three ways of getting the directory until one
+ // produces a directory I can write to.
public static File getDownloadDir( Context context )
{
File result = null;
- if ( null != s_dirGetter ) {
- result = s_dirGetter.getDownloadDir();
- }
- if ( null != result ) {
- // we're done
- } else if ( haveWriteableSD() ) {
- File file = null;
- String myPath = XWPrefs.getMyDownloadDir( context );
- if ( null != myPath && 0 < myPath.length() ) {
- file = new File( myPath );
- } else {
- file = Environment.getExternalStorageDirectory();
- if ( null != file ) {
- File child = new File( file, "download/" );
- if ( child.exists() && child.isDirectory()
- && child.canWrite() ) {
- file = child;
- }
+ outer:
+ for ( int attempt = 0; attempt < 4; ++attempt ) {
+ switch ( attempt ) {
+ case 0:
+ String myPath = XWPrefs.getMyDownloadDir( context );
+ if ( null == myPath || 0 == myPath.length() ) {
+ continue;
}
+ result = new File( myPath );
+ break;
+ case 1:
+ if ( null == s_dirGetter ) {
+ continue;
+ }
+ result = s_dirGetter.getDownloadDir();
+ break;
+ case 2:
+ case 3:
+ if ( !haveWriteableSD() ) {
+ continue;
+ }
+ result = Environment.getExternalStorageDirectory();
+ if ( 2 == attempt && null != result ) {
+ // the old way...
+ result = new File( result, "download/" );
+ }
+ break;
}
- if ( null != file && file.exists() && file.isDirectory() ) {
- result = file;
+
+ // Exit test for loop
+ if ( null != result ) {
+ if ( result.exists() && result.isDirectory() && result.canWrite() ) {
+ break outer;
+ }
}
}
return result;
@@ -631,9 +639,6 @@ public class DictUtils {
{
File path = Environment.
getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
- if ( null != path && !path.canWrite() ) {
- path = null;
- }
return path;
}
}
From e719c6e61d0cf0b5e760d222b7b29823571d6090 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Wed, 5 Dec 2012 08:15:48 -0800
Subject: [PATCH 109/146] don't crash if for some reason json file can't be
written
---
.../src/org/eehouse/android/xw4/GameUtils.java | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
index 52b274823..420819c46 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
@@ -533,18 +533,22 @@ public class GameUtils {
intent.putExtra( Intent.EXTRA_SUBJECT, subject );
intent.putExtra( Intent.EXTRA_TEXT, Html.fromHtml(message) );
+ File attach = null;
File tmpdir = XWApp.ATTACH_SUPPORTED ?
DictUtils.getDownloadDir( context ) : null;
- if ( null == tmpdir ) { // no attachment
+ if ( null != tmpdir ) { // no attachment
+ attach = makeJsonFor( tmpdir, room, inviteID, lang,
+ dict, nPlayers );
+ }
+
+ if ( null == attach ) { // no attachment
intent.setType( "message/rfc822");
} else {
- intent.setType( context.getString( R.string.invite_mime ) );
-
- File attach = makeJsonFor( tmpdir, room, inviteID, lang,
- dict, nPlayers );
+ String mime = context.getString( R.string.invite_mime );
+ intent.setType( mime );
Uri uri = Uri.fromFile( attach );
- DbgUtils.logf( "using file uri for attachment: %s",
- uri.toString() );
+ DbgUtils.logf( "using file uri %s, type %s for attachment",
+ uri.toString(), mime );
intent.putExtra( Intent.EXTRA_STREAM, uri );
}
From 93bf2a1b3ec2c7e23aa7051acc97df49699319b3 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Wed, 5 Dec 2012 19:15:20 -0800
Subject: [PATCH 110/146] hard-code tiles drawn nearly-square, just to see what
it looks like. Making them exactly square would probably take a new jni call.
And if I ship this it needs to be optional, controlled by a preference.
---
.../XWords4/src/org/eehouse/android/xw4/BoardView.java | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardView.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardView.java
index eea07b086..d05909c99 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardView.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardView.java
@@ -53,6 +53,8 @@ public class BoardView extends View implements DrawCtx, BoardHandler,
private static final int PINCH_THRESHOLD = 40;
private static final int SCORE_HT_DROP = 2;
private static final boolean DEBUG_DRAWFRAMES = false;
+ // this can be a preference
+ private static final boolean MAKETILESSQUARE = true;
private Context m_context;
private Paint m_drawPaint;
@@ -379,8 +381,12 @@ public class BoardView extends View implements DrawCtx, BoardHandler,
heightLeft = cellSize * 3 / 2;
}
heightLeft /= 3;
- trayHt += heightLeft * 2;
scoreHt += heightLeft;
+
+ trayHt += heightLeft * 2;
+ if ( MAKETILESSQUARE && trayHt > width / 7 ) {
+ trayHt = width / 7;
+ }
heightUsed = trayHt + scoreHt + ((nCells - nToScroll) * cellSize);
}
From 83b1d4c364f4c76c0ececde36873d7b480c3f004 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Sat, 8 Dec 2012 06:40:21 -0800
Subject: [PATCH 111/146] fix compiler warnings
---
xwords4/common/game.c | 14 +++++++++-----
xwords4/common/server.c | 2 +-
2 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/xwords4/common/game.c b/xwords4/common/game.c
index f61e25ab2..ae73da301 100644
--- a/xwords4/common/game.c
+++ b/xwords4/common/game.c
@@ -93,10 +93,12 @@ game_makeNewGame( MPFORMAL XWGame* game, CurGameInfo* gi,
#endif
)
{
- XP_U16 nPlayersHere, nPlayersTotal;
-
- assertUtilOK( util );
+#ifndef XWFEATURE_STANDALONE_ONLY
+ XP_U16 nPlayersHere = 0;
+ XP_U16 nPlayersTotal = 0;
checkServerRole( gi, &nPlayersHere, &nPlayersTotal );
+#endif
+ assertUtilOK( util );
gi->gameID = makeGameID( util );
@@ -137,15 +139,17 @@ game_reset( MPFORMAL XWGame* game, CurGameInfo* gi,
CommonPrefs* cp, const TransportProcs* procs )
{
XP_U16 ii;
- XP_U16 nPlayersHere, nPlayersTotal;
XP_ASSERT( !!game->model );
XP_ASSERT( !!gi );
- checkServerRole( gi, &nPlayersHere, &nPlayersTotal );
gi->gameID = makeGameID( util );
#ifndef XWFEATURE_STANDALONE_ONLY
+ XP_U16 nPlayersHere = 0;
+ XP_U16 nPlayersTotal = 0;
+ checkServerRole( gi, &nPlayersHere, &nPlayersTotal );
+
if ( !!game->comms ) {
if ( gi->serverRole == SERVER_STANDALONE ) {
comms_destroy( game->comms );
diff --git a/xwords4/common/server.c b/xwords4/common/server.c
index 95e4c0759..aebb41ab2 100644
--- a/xwords4/common/server.c
+++ b/xwords4/common/server.c
@@ -686,7 +686,7 @@ handleRegistrationMsg( ServerCtxt* server, XWStreamCtxt* stream )
{
XP_Bool success = XP_TRUE;
XP_U16 playersInMsg;
- XP_S8 clientIndex;
+ XP_S8 clientIndex = 0; /* quiet compiler */
XP_U16 ii = 0;
LOG_FUNC();
From 7efbd2697d3ab8a55e9d131d8a64c7266a98df24 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Sat, 8 Dec 2012 08:47:53 -0800
Subject: [PATCH 112/146] rewrite list item logic. Use a single custom
LinearLayout subclass for both the loading and loaded phases, toggling its
state once the data's available. Reuse it: pay attention to what's passed
into getView and only allocate when there's no existing View to reuse. Stop
caching Views, as that defeats Android list logic that might limit in-memory
representation to the subset that's visible on-screen, instead tracking a set
of rowids whose data is known to be good as a way of quickly drawing when
there's a refresh.
---
.../XWords4/res/layout/game_list_item.xml | 185 ++++----
.../eehouse/android/xw4/GameListAdapter.java | 431 ++++++++----------
.../org/eehouse/android/xw4/GameListItem.java | 115 +++++
.../org/eehouse/android/xw4/GamesList.java | 8 +-
.../eehouse/android/xw4/XWListAdapter.java | 5 +-
5 files changed, 420 insertions(+), 324 deletions(-)
create mode 100644 xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListItem.java
diff --git a/xwords4/android/XWords4/res/layout/game_list_item.xml b/xwords4/android/XWords4/res/layout/game_list_item.xml
index 1a6ab2cb1..771af6471 100644
--- a/xwords4/android/XWords4/res/layout/game_list_item.xml
+++ b/xwords4/android/XWords4/res/layout/game_list_item.xml
@@ -3,95 +3,114 @@
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:visibility="gone"
+ >
-
-
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java
index bcdfbefe3..87b65e852 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java
@@ -35,7 +35,7 @@ import android.widget.TextView;
import java.io.FileInputStream;
import java.text.DateFormat;
import java.util.Date;
-import java.util.HashMap; // class is not synchronized
+import java.util.HashSet;
import java.util.Random;
import junit.framework.Assert;
@@ -46,10 +46,6 @@ import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole;
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
public class GameListAdapter extends XWListAdapter {
- private Context m_context;
- private LayoutInflater m_factory;
- private int m_fieldID;
- private Handler m_handler;
private static final boolean s_isFire;
private static Random s_random;
static {
@@ -59,79 +55,35 @@ public class GameListAdapter extends XWListAdapter {
}
}
- private class ViewInfo implements View.OnClickListener {
- private View m_view;
- private View m_hideable;
- private ExpiringTextView m_name;
- private boolean m_expanded, m_haveTurn, m_haveTurnLocal;
- private long m_rowid;
- private long m_lastMoveTime;
- private ImageButton m_expandButton;
-
- public ViewInfo( View view, long rowid )
- {
- m_view = view;
- m_rowid = rowid;
- m_lastMoveTime = 0;
- }
-
- public ViewInfo( View view, long rowid, boolean expanded,
- long lastMoveTime, boolean haveTurn,
- boolean haveTurnLocal ) {
- this( view, rowid );
- m_expanded = expanded;
- m_lastMoveTime = lastMoveTime;
- m_haveTurn = haveTurn;
- m_haveTurnLocal = haveTurnLocal;
- m_hideable = (LinearLayout)view.findViewById( R.id.hideable );
- m_name = (ExpiringTextView)m_view.findViewById( R.id.game_name );
- m_expandButton = (ImageButton)view.findViewById( R.id.expander );
- m_expandButton.setOnClickListener( this );
- showHide();
- }
-
- private void showHide()
- {
- m_expandButton.setImageResource( m_expanded ?
- R.drawable.expander_ic_maximized :
- R.drawable.expander_ic_minimized);
- m_hideable.setVisibility( m_expanded? View.VISIBLE : View.GONE );
-
- m_name.setBackgroundColor( android.R.color.transparent );
- m_name.setPct( m_handler, m_haveTurn && !m_expanded,
- m_haveTurnLocal, m_lastMoveTime );
- }
-
- public void onClick( View view ) {
- m_expanded = !m_expanded;
- DBUtils.setExpanded( m_rowid, m_expanded );
- showHide();
- }
- }
-
- private HashMap m_viewsCache;
+ private Context m_context;
+ private LayoutInflater m_factory;
+ private int m_fieldID;
+ private Handler m_handler;
private DateFormat m_df;
private LoadItemCB m_cb;
-
+ // Track those rows known to be good. If a rowid is not in this
+ // set, assume it must be loaded. Add rowids to this set as
+ // they're loaded, and remove one when when it must be redrawn.
+ private HashSet m_loadedRows;
public interface LoadItemCB {
- public void itemLoaded( long rowid );
public void itemClicked( long rowid );
}
- private class LoadItemTask extends AsyncTask {
- private long m_rowid;
+ private class LoadItemTask extends AsyncTask {
+ private GameListItem m_view;
private Context m_context;
// private int m_id;
- public LoadItemTask( Context context, long rowid/*, int id*/ )
+ public LoadItemTask( Context context, GameListItem view )
{
+ DbgUtils.logf( "Creating LoadItemTask for row %d",
+ view.getRowID() );
m_context = context;
- m_rowid = rowid;
- // m_id = id;
+ m_view = view;
}
@Override
- protected Void doInBackground( Void... unused )
+ protected GameSummary doInBackground( Void... unused )
{
// Without this, on the Fire only the last item in the
// list it tappable. Likely my fault, but this seems to
@@ -143,133 +95,26 @@ public class GameListAdapter extends XWListAdapter {
} catch ( Exception e ) {
}
}
- View layout = m_factory.inflate( R.layout.game_list_item, null );
- boolean hideTitle = false;//CommonPrefs.getHideTitleBar(m_context);
- GameSummary summary = DBUtils.getSummary( m_context, m_rowid, 1500 );
- if ( null == summary ) {
- m_rowid = -1;
- } else {
- String state = summary.summarizeState();
- TextView view = (TextView)layout.findViewById( R.id.game_name );
- if ( hideTitle ) {
- view.setVisibility( View.GONE );
- } else {
- String value = null;
- switch ( m_fieldID ) {
- case R.string.game_summary_field_empty:
- break;
- case R.string.game_summary_field_language:
- value =
- DictLangCache.getLangName( m_context,
- summary.dictLang );
- break;
- case R.string.game_summary_field_opponents:
- value = summary.playerNames();
- break;
- case R.string.game_summary_field_state:
- value = state;
- break;
- }
-
- String name = GameUtils.getName( m_context, m_rowid );
-
- if ( null != value ) {
- value = m_context.getString( R.string.str_game_namef,
- name, value );
- } else {
- value = name;
- }
-
- view.setText( value );
- }
-
- layout.setOnClickListener( new View.OnClickListener() {
- @Override
- public void onClick( View v ) {
- m_cb.itemClicked( m_rowid );
- }
- } );
-
- LinearLayout list =
- (LinearLayout)layout.findViewById( R.id.player_list );
- boolean haveATurn = false;
- boolean haveALocalTurn = false;
- boolean[] isLocal = new boolean[1];
- for ( int ii = 0; ii < summary.nPlayers; ++ii ) {
- ExpiringLinearLayout tmp = (ExpiringLinearLayout)
- m_factory.inflate( R.layout.player_list_elem, null );
- view = (TextView)tmp.findViewById( R.id.item_name );
- view.setText( summary.summarizePlayer( ii ) );
- view = (TextView)tmp.findViewById( R.id.item_score );
- view.setText( String.format( " %d", summary.scores[ii] ) );
- boolean thisHasTurn = summary.isNextToPlay( ii, isLocal );
- if ( thisHasTurn ) {
- haveATurn = true;
- if ( isLocal[0] ) {
- haveALocalTurn = true;
- }
- }
- tmp.setPct( m_handler, thisHasTurn, isLocal[0],
- summary.lastMoveTime );
- list.addView( tmp, ii );
- }
-
- view = (TextView)layout.findViewById( R.id.state );
- view.setText( state );
- view = (TextView)layout.findViewById( R.id.modtime );
- long lastMoveTime = summary.lastMoveTime;
- lastMoveTime *= 1000;
- view.setText( m_df.format( new Date( lastMoveTime ) ) );
-
- int iconID;
- ImageView marker =
- (ImageView)layout.findViewById( R.id.msg_marker );
- CommsConnType conType = summary.conType;
- if ( CommsConnType.COMMS_CONN_RELAY == conType ) {
- iconID = R.drawable.relaygame;
- } else if ( CommsConnType.COMMS_CONN_BT == conType ) {
- iconID = android.R.drawable.stat_sys_data_bluetooth;
- } else if ( CommsConnType.COMMS_CONN_SMS == conType ) {
- iconID = android.R.drawable.sym_action_chat;
- } else {
- iconID = R.drawable.sologame;
- }
- marker.setImageResource( iconID );
-
- view = (TextView)layout.findViewById( R.id.role );
- String roleSummary = summary.summarizeRole();
- if ( null != roleSummary ) {
- view.setText( roleSummary );
- } else {
- view.setVisibility( View.GONE );
- }
-
- boolean expanded = DBUtils.getExpanded( m_context, m_rowid );
- ViewInfo vi = new ViewInfo( layout, m_rowid, expanded,
- summary.lastMoveTime, haveATurn,
- haveALocalTurn );
- if ( XWApp.DEBUG ) {
- DbgUtils.logf( "created new view for rowid %d", m_rowid );
- }
- synchronized( m_viewsCache ) {
- m_viewsCache.put( m_rowid, vi );
- }
- }
- return null;
+ long rowid = m_view.getRowID();
+ GameSummary summary = DBUtils.getSummary( m_context, rowid, 1500 );
+ return summary;
} // doInBackground
@Override
- protected void onPostExecute( Void unused )
+ protected void onPostExecute( GameSummary summary )
{
- // DbgUtils.logf( "onPostExecute(rowid=%d)", m_rowid );
- if ( -1 != m_rowid ) {
- m_cb.itemLoaded( m_rowid );
- }
+ setData( m_view, summary );
+ setLoaded( m_view.getRowID() );
+ m_view.setLoaded( true );
+
+ DbgUtils.logf( "LoadItemTask for row %d finished",
+ m_view.getRowID() );
}
} // class LoadItemTask
- public GameListAdapter( Context context, Handler handler, LoadItemCB cb ) {
+ public GameListAdapter( Context context, Handler handler, LoadItemCB cb,
+ String fieldName ) {
super( DBUtils.gamesList(context).length );
m_context = context;
m_handler = handler;
@@ -278,62 +123,92 @@ public class GameListAdapter extends XWListAdapter {
m_df = DateFormat.getDateTimeInstance( DateFormat.SHORT,
DateFormat.SHORT );
- m_viewsCache = new HashMap();
+ m_loadedRows = new HashSet();
+ m_fieldID = fieldToID( fieldName );
}
-
+
+ @Override
public int getCount() {
return DBUtils.gamesList(m_context).length;
}
-
- public Object getItem( int position )
+
+ // Views. A view depends on a summary, which takes time to load.
+ // When one needs loading it's done via an async task.
+ public View getView( int position, View convertView, ViewGroup parent )
{
- final long rowid = DBUtils.gamesList(m_context)[position];
- View layout;
- boolean haveLayout = false;
- synchronized( m_viewsCache ) {
- ViewInfo vi = m_viewsCache.get( rowid );
- haveLayout = null != vi;
- if ( haveLayout ) {
- layout = vi.m_view;
- } else {
- layout = m_factory.inflate( R.layout.game_list_tmp, null );
- vi = new ViewInfo( layout, rowid );
- m_viewsCache.put( rowid, vi );
+ GameListItem result;
+ boolean mustLoad = false;
+ if ( null == convertView ) {
+ result = (GameListItem)
+ m_factory.inflate( R.layout.game_list_item, null );
+ result.setRowID( DBUtils.gamesList(m_context)[position] );
+ mustLoad = true;
+ } else {
+ result = (GameListItem)convertView;
+ long rowid = result.getRowID();
+ if ( isDirty(rowid) || !result.isLoaded() ) {
+ mustLoad = true;
}
}
- if ( !haveLayout ) {
- new LoadItemTask( m_context, rowid/*, ++m_taskCounter*/ ).execute();
+ if ( mustLoad ) {
+ new LoadItemTask( m_context, result ).execute();
}
- // this doesn't work. Rather, it breaks highlighting because
- // the background, if we don't set it, is a more complicated
- // object like @android:drawable/list_selector_background. I
- // tried calling getBackground(), expecting to get a Drawable
- // I could then clone and modify, but null comes back. So
- // layout must be inheriting its background from elsewhere or
- // it gets set later, during layout.
- // if ( (position%2) == 0 ) {
- // layout.setBackgroundColor( 0xFF3F3F3F );
- // }
-
- return layout;
- } // getItem
-
- public View getView( int position, View convertView, ViewGroup parent ) {
- return (View)getItem( position );
+ return result;
}
public void inval( long rowid )
{
- synchronized( m_viewsCache ) {
- m_viewsCache.remove( rowid );
+ synchronized( m_loadedRows ) {
+ m_loadedRows.remove( rowid );
+ }
+ }
+
+ private void dirtyAll()
+ {
+ synchronized( m_loadedRows ) {
+ m_loadedRows.clear();
+ }
+ }
+
+ private boolean isDirty( long rowid )
+ {
+ synchronized( m_loadedRows ) {
+ return ! m_loadedRows.contains( rowid );
+ }
+ }
+
+ private void setLoaded( long rowid )
+ {
+ synchronized( m_loadedRows ) {
+ m_loadedRows.add( rowid );
}
}
public boolean setField( String fieldName )
{
boolean changed = false;
+ int newID = fieldToID( fieldName );
+ if ( -1 == newID ) {
+ if ( XWApp.DEBUG ) {
+ DbgUtils.logf( "GameListAdapter.setField(): unable to match"
+ + " fieldName %s", fieldName );
+ }
+ } else if ( m_fieldID != newID ) {
+ if ( XWApp.DEBUG ) {
+ DbgUtils.logf( "setField: clearing views cache for change"
+ + " from %d to %d", m_fieldID, newID );
+ }
+ m_fieldID = newID;
+ dirtyAll();
+ changed = true;
+ }
+ return changed;
+ }
+
+ private int fieldToID( String fieldName )
+ {
int[] ids = {
R.string.game_summary_field_empty
,R.string.game_summary_field_language
@@ -347,21 +222,109 @@ public class GameListAdapter extends XWListAdapter {
break;
}
}
- if ( -1 == result ) {
- if ( XWApp.DEBUG ) {
- DbgUtils.logf( "GameListAdapter.setField(): unable to match"
- + " fieldName %s", fieldName );
- }
- } else if ( m_fieldID != result ) {
- if ( XWApp.DEBUG ) {
- DbgUtils.logf( "setField: clearing views cache for change"
- + " from %d to %d", m_fieldID, result );
- }
- m_viewsCache.clear();
- m_fieldID = result;
- changed = true;
- }
- return changed;
+ return result;
}
+ private void setData( GameListItem layout, GameSummary summary )
+ {
+ if ( null != summary ) {
+ final long rowid = layout.getRowID();
+ String state = summary.summarizeState();
+
+ TextView view = (TextView)layout.findViewById( R.id.game_name );
+ String value = null;
+ switch ( m_fieldID ) {
+ case R.string.game_summary_field_empty:
+ break;
+ case R.string.game_summary_field_language:
+ value =
+ DictLangCache.getLangName( m_context,
+ summary.dictLang );
+ break;
+ case R.string.game_summary_field_opponents:
+ value = summary.playerNames();
+ break;
+ case R.string.game_summary_field_state:
+ value = state;
+ break;
+ }
+
+ String name = GameUtils.getName( m_context, rowid );
+
+ if ( null != value ) {
+ value = m_context.getString( R.string.str_game_namef,
+ name, value );
+ } else {
+ value = name;
+ }
+
+ view.setText( value );
+
+ layout.setOnClickListener( new View.OnClickListener() {
+ @Override
+ public void onClick( View v ) {
+ m_cb.itemClicked( rowid );
+ }
+ } );
+
+ LinearLayout list =
+ (LinearLayout)layout.findViewById( R.id.player_list );
+ boolean haveATurn = false;
+ boolean haveALocalTurn = false;
+ boolean[] isLocal = new boolean[1];
+ for ( int ii = 0; ii < summary.nPlayers; ++ii ) {
+ ExpiringLinearLayout tmp = (ExpiringLinearLayout)
+ m_factory.inflate( R.layout.player_list_elem, null );
+ view = (TextView)tmp.findViewById( R.id.item_name );
+ view.setText( summary.summarizePlayer( ii ) );
+ view = (TextView)tmp.findViewById( R.id.item_score );
+ view.setText( String.format( " %d", summary.scores[ii] ) );
+ boolean thisHasTurn = summary.isNextToPlay( ii, isLocal );
+ if ( thisHasTurn ) {
+ haveATurn = true;
+ if ( isLocal[0] ) {
+ haveALocalTurn = true;
+ }
+ }
+ tmp.setPct( m_handler, thisHasTurn, isLocal[0],
+ summary.lastMoveTime );
+ list.addView( tmp, ii );
+ }
+
+ view = (TextView)layout.findViewById( R.id.state );
+ view.setText( state );
+ view = (TextView)layout.findViewById( R.id.modtime );
+ long lastMoveTime = summary.lastMoveTime;
+ lastMoveTime *= 1000;
+ view.setText( m_df.format( new Date( lastMoveTime ) ) );
+
+ int iconID;
+ ImageView marker =
+ (ImageView)layout.findViewById( R.id.msg_marker );
+ CommsConnType conType = summary.conType;
+ if ( CommsConnType.COMMS_CONN_RELAY == conType ) {
+ iconID = R.drawable.relaygame;
+ } else if ( CommsConnType.COMMS_CONN_BT == conType ) {
+ iconID = android.R.drawable.stat_sys_data_bluetooth;
+ } else if ( CommsConnType.COMMS_CONN_SMS == conType ) {
+ iconID = android.R.drawable.sym_action_chat;
+ } else {
+ iconID = R.drawable.sologame;
+ }
+ marker.setImageResource( iconID );
+
+ view = (TextView)layout.findViewById( R.id.role );
+ String roleSummary = summary.summarizeRole();
+ if ( null != roleSummary ) {
+ view.setText( roleSummary );
+ } else {
+ view.setVisibility( View.GONE );
+ }
+
+ boolean expanded = DBUtils.getExpanded( m_context, rowid );
+
+ layout.update( m_handler, expanded, summary.lastMoveTime,
+ haveATurn, haveALocalTurn );
+ }
+ }
}
\ No newline at end of file
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListItem.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListItem.java
new file mode 100644
index 000000000..fb03482d2
--- /dev/null
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListItem.java
@@ -0,0 +1,115 @@
+/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
+/*
+ * Copyright 2009-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.content.Context;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+
+public class GameListItem extends LinearLayout
+ implements View.OnClickListener {
+
+ private Context m_context;
+ private boolean m_loaded;
+ private long m_rowid;
+ private View m_hideable;
+ private ExpiringTextView m_name;
+ private boolean m_expanded, m_haveTurn, m_haveTurnLocal;
+ private long m_lastMoveTime;
+ private ImageButton m_expandButton;
+ private Handler m_handler;
+
+ public GameListItem( Context cx, AttributeSet as )
+ {
+ super( cx, as );
+ m_context = cx;
+ m_loaded = false;
+ m_rowid = DBUtils.ROWID_NOTFOUND;
+ m_lastMoveTime = 0;
+ }
+
+ public void update( Handler handler, boolean expanded,
+ long lastMoveTime, boolean haveTurn,
+ boolean haveTurnLocal )
+ {
+ m_handler = handler;
+ m_expanded = expanded;
+ m_lastMoveTime = lastMoveTime;
+ m_haveTurn = haveTurn;
+ m_haveTurnLocal = haveTurnLocal;
+ m_hideable = (LinearLayout)findViewById( R.id.hideable );
+ m_name = (ExpiringTextView)findViewById( R.id.game_name );
+ m_expandButton = (ImageButton)findViewById( R.id.expander );
+ m_expandButton.setOnClickListener( this );
+ showHide();
+ }
+
+ public void setLoaded( boolean loaded )
+ {
+ if ( m_loaded != loaded ) {
+ m_loaded = loaded;
+ // This should be enough to invalidate
+ findViewById( R.id.view_unloaded )
+ .setVisibility( loaded ? View.GONE : View.VISIBLE );
+ findViewById( R.id.view_loaded )
+ .setVisibility( loaded ? View.VISIBLE : View.GONE );
+ }
+ }
+
+ public boolean isLoaded()
+ {
+ return m_loaded;
+ }
+
+ public void setRowID( long rowid )
+ {
+ m_rowid = rowid;
+ }
+
+ public long getRowID()
+ {
+ return m_rowid;
+ }
+
+ // View.OnClickListener interface
+ public void onClick( View view ) {
+ m_expanded = !m_expanded;
+ DBUtils.setExpanded( m_rowid, m_expanded );
+ showHide();
+ }
+
+ private void showHide()
+ {
+ m_expandButton.setImageResource( m_expanded ?
+ R.drawable.expander_ic_maximized :
+ R.drawable.expander_ic_minimized);
+ m_hideable.setVisibility( m_expanded? View.VISIBLE : View.GONE );
+
+ m_name.setBackgroundColor( android.R.color.transparent );
+ m_name.setPct( m_handler, m_haveTurn && !m_expanded,
+ m_haveTurnLocal, m_lastMoveTime );
+ }
+
+
+}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
index fbed5b9d7..3bb68c661 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
@@ -282,7 +282,8 @@ public class GamesList extends XWListActivity
}
});
- m_adapter = new GameListAdapter( this, new Handler(), this );
+ String field = CommonPrefs.getSummaryField( this );
+ m_adapter = new GameListAdapter( this, new Handler(), this, field );
setListAdapter( m_adapter );
NetUtils.informOfDeaths( this );
@@ -391,11 +392,6 @@ public class GamesList extends XWListActivity
}
// GameListAdapter.LoadItemCB interface
- public void itemLoaded( long rowid )
- {
- onContentChanged();
- }
-
public void itemClicked( long rowid )
{
// We need a way to let the user get back to the basic-config
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListAdapter.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListAdapter.java
index 069191e81..52306419b 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListAdapter.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListAdapter.java
@@ -41,8 +41,11 @@ public abstract class XWListAdapter implements ListAdapter {
public boolean areAllItemsEnabled() { return true; }
public boolean isEnabled( int position ) { return true; }
public int getCount() { return m_count; }
+ public Object getItem( int position ) { return null; }
public long getItemId(int position) { return position; }
- public int getItemViewType(int position) { return 0; }
+ public int getItemViewType( int position ) {
+ return ListAdapter.IGNORE_ITEM_VIEW_TYPE;
+ }
public int getViewTypeCount() { return 1; }
public boolean hasStableIds() { return true; }
public boolean isEmpty() { return getCount() == 0; }
From ce803a928cdcc3f50ef475b5ba8c2f3613f9e601 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Sat, 8 Dec 2012 08:55:45 -0800
Subject: [PATCH 113/146] pass summary rather than have callee refetch it
---
.../src/org/eehouse/android/xw4/GameListAdapter.java | 6 +++---
.../XWords4/src/org/eehouse/android/xw4/GamesList.java | 3 +--
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java
index 87b65e852..9693a0eba 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java
@@ -67,7 +67,7 @@ public class GameListAdapter extends XWListAdapter {
private HashSet m_loadedRows;
public interface LoadItemCB {
- public void itemClicked( long rowid );
+ public void itemClicked( long rowid, GameSummary summary );
}
private class LoadItemTask extends AsyncTask {
@@ -225,7 +225,7 @@ public class GameListAdapter extends XWListAdapter {
return result;
}
- private void setData( GameListItem layout, GameSummary summary )
+ private void setData( GameListItem layout, final GameSummary summary )
{
if ( null != summary ) {
final long rowid = layout.getRowID();
@@ -263,7 +263,7 @@ public class GameListAdapter extends XWListAdapter {
layout.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick( View v ) {
- m_cb.itemClicked( rowid );
+ m_cb.itemClicked( rowid, summary );
}
} );
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
index 3bb68c661..99697680b 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
@@ -392,12 +392,11 @@ public class GamesList extends XWListActivity
}
// GameListAdapter.LoadItemCB interface
- public void itemClicked( long rowid )
+ public void itemClicked( long rowid, GameSummary summary )
{
// We need a way to let the user get back to the basic-config
// dialog in case it was dismissed. That way it to check for
// an empty room name.
- GameSummary summary = DBUtils.getSummary( this, rowid );
if ( summary.conType == CommsAddrRec.CommsConnType.COMMS_CONN_RELAY
&& summary.roomName.length() == 0 ) {
// If it's unconfigured and of the type RelayGameActivity
From 3a45db66cf6a3b50580445959b811704b2e1b0a4 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Sat, 8 Dec 2012 20:28:11 -0800
Subject: [PATCH 114/146] cache array of rowids, and clear cache appropriately,
rather than query DB for all games every time.
---
.../src/org/eehouse/android/xw4/DBUtils.java | 56 ++++++++++++-------
1 file changed, 37 insertions(+), 19 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
index 303b09af9..e656377e7 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
@@ -60,6 +60,7 @@ public class DBUtils {
private static long s_cachedRowID = -1;
private static byte[] s_cachedBytes = null;
+ private static long[] s_cachedRowIDs = null;
public static interface DBChangeListener {
public void gameSaved( long rowid );
@@ -314,6 +315,9 @@ public class DBUtils {
long result = db.update( DBHelper.TABLE_NAME_SUM,
values, selection, null );
Assert.assertTrue( result >= 0 );
+ if ( result != rowid ) { // new row added
+ clearRowIDsCache();
+ }
}
notifyListeners( rowid );
db.close();
@@ -675,7 +679,8 @@ public class DBUtils {
}
}
- public static GameUtils.GameLock saveNewGame( Context context, byte[] bytes )
+ public static GameUtils.GameLock saveNewGame( Context context,
+ byte[] bytes )
{
GameUtils.GameLock lock = null;
@@ -695,9 +700,9 @@ public class DBUtils {
long rowid = db.insert( DBHelper.TABLE_NAME_SUM, null, values );
setCached( rowid, null ); // force reread
+ clearRowIDsCache();
lock = new GameUtils.GameLock( rowid, true ).lock();
-
notifyListeners( rowid );
}
@@ -771,34 +776,47 @@ public class DBUtils {
db.delete( DBHelper.TABLE_NAME_SUM, selection, null );
db.close();
}
+ clearRowIDsCache();
notifyListeners( lock.getRowid() );
}
public static long[] gamesList( Context context )
{
- long[] result = null;
+ long[] result;
+ synchronized( DBUtils.class ) {
+ if ( null == s_cachedRowIDs ) {
+ initDB( context );
+ synchronized( s_dbHelper ) {
+ SQLiteDatabase db = s_dbHelper.getReadableDatabase();
- initDB( context );
- synchronized( s_dbHelper ) {
- SQLiteDatabase db = s_dbHelper.getReadableDatabase();
-
- String[] columns = { ROW_ID };
- String orderBy = DBHelper.CREATE_TIME + " DESC";
- Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
- null, null, null, null, orderBy );
- int count = cursor.getCount();
- result = new long[count];
- int index = cursor.getColumnIndex( ROW_ID );
- for ( int ii = 0; cursor.moveToNext(); ++ii ) {
- result[ii] = cursor.getLong( index );
+ String[] columns = { ROW_ID };
+ String orderBy = DBHelper.CREATE_TIME + " DESC";
+ Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM,
+ columns, null, null, null,
+ null, orderBy );
+ int count = cursor.getCount();
+ s_cachedRowIDs = new long[count];
+ int index = cursor.getColumnIndex( ROW_ID );
+ for ( int ii = 0; cursor.moveToNext(); ++ii ) {
+ s_cachedRowIDs[ii] = cursor.getLong( index );
+ }
+ cursor.close();
+ db.close();
+ }
}
- cursor.close();
- db.close();
+ result = s_cachedRowIDs;
}
-
return result;
}
+ private static void clearRowIDsCache()
+ {
+ DbgUtils.logf( "DBUtils.clearRowIDsCache()" );
+ synchronized( DBUtils.class ) {
+ s_cachedRowIDs = null;
+ }
+ }
+
// Get either the file name or game name, preferring the latter.
public static String getName( Context context, long rowid )
{
From 1bc8070bb1bb3c0141e9e289d277550201404bc6 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Mon, 10 Dec 2012 07:11:13 -0800
Subject: [PATCH 115/146] disable Rematch button (for now)
---
.../XWords4/src/org/eehouse/android/xw4/BoardActivity.java | 2 +-
xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
index 9998ba315..e638df480 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
@@ -248,7 +248,7 @@ public class BoardActivity extends XWActivity
}
};
ab.setNegativeButton( R.string.button_retry, lstnr );
- } else if ( GAME_OVER == id ) {
+ } else if ( XWApp.REMATCH_SUPPORTED && GAME_OVER == id ) {
lstnr = new DialogInterface.OnClickListener() {
public void onClick( DialogInterface dlg,
int whichButton ) {
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java
index 57927412b..24edc0066 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java
@@ -33,6 +33,7 @@ public class XWApp extends Application {
public static final boolean SMSSUPPORTED = true;
public static final boolean GCMSUPPORTED = true;
public static final boolean ATTACH_SUPPORTED = true;
+ public static final boolean REMATCH_SUPPORTED = false;
public static final boolean DEBUG = true; // DON'T SHIP THIS WAY
public static final String SMS_PUBLIC_HEADER = "-XW4";
From d820554ffba3ae463a4105809b2123ee1936440b Mon Sep 17 00:00:00 2001
From: Eric House
Date: Mon, 10 Dec 2012 07:48:15 -0800
Subject: [PATCH 116/146] change game list item strategy since it turns out
adapter's findView() doesn't pass in the previous representation of a given
item for recycling: move async loading of summary into GameListItem class,
and use getChildAt() to invalidate a single list (rather than reloading the
whole list) whereever possible. Still need to dump the list whenever the
number of items changes since we're depending on DBUtils to determine the
order and have no way to reshuffle existing items.
---
.../src/org/eehouse/android/xw4/DBUtils.java | 18 +-
.../eehouse/android/xw4/GameListAdapter.java | 236 +++---------------
.../org/eehouse/android/xw4/GameListItem.java | 203 +++++++++++++--
.../org/eehouse/android/xw4/GamesList.java | 21 +-
.../eehouse/android/xw4/XWListAdapter.java | 6 +-
5 files changed, 241 insertions(+), 243 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
index e656377e7..8deebeeaa 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
@@ -63,7 +63,7 @@ public class DBUtils {
private static long[] s_cachedRowIDs = null;
public static interface DBChangeListener {
- public void gameSaved( long rowid );
+ public void gameSaved( long rowid, boolean countChanged );
}
private static HashSet s_listeners =
new HashSet();
@@ -319,8 +319,8 @@ public class DBUtils {
clearRowIDsCache();
}
}
- notifyListeners( rowid );
db.close();
+ notifyListeners( rowid, false );
}
} // saveSummary
@@ -376,7 +376,7 @@ public class DBUtils {
public static void setMsgFlags( long rowid, int flags )
{
setInt( rowid, DBHelper.HASMSGS, flags );
- notifyListeners( rowid );
+ notifyListeners( rowid, false );
}
public static void setExpanded( long rowid, boolean expanded )
@@ -703,7 +703,7 @@ public class DBUtils {
clearRowIDsCache();
lock = new GameUtils.GameLock( rowid, true ).lock();
- notifyListeners( rowid );
+ notifyListeners( rowid, true );
}
return lock;
@@ -727,8 +727,8 @@ public class DBUtils {
updateRow( context, DBHelper.TABLE_NAME_SUM, rowid, values );
setCached( rowid, null ); // force reread
- if ( -1 != rowid ) { // Is this possible? PENDING
- notifyListeners( rowid );
+ if ( -1 != rowid ) { // Means new game?
+ notifyListeners( rowid, false );
}
return rowid;
}
@@ -777,7 +777,7 @@ public class DBUtils {
db.close();
}
clearRowIDsCache();
- notifyListeners( lock.getRowid() );
+ notifyListeners( lock.getRowid(), true );
}
public static long[] gamesList( Context context )
@@ -1223,12 +1223,12 @@ public class DBUtils {
}
}
- private static void notifyListeners( long rowid )
+ private static void notifyListeners( long rowid, boolean countChanged )
{
synchronized( s_listeners ) {
Iterator iter = s_listeners.iterator();
while ( iter.hasNext() ) {
- iter.next().gameSaved( rowid );
+ iter.next().gameSaved( rowid, countChanged );
}
}
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java
index 9693a0eba..26405c0a2 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java
@@ -21,7 +21,6 @@ package org.eehouse.android.xw4;
import android.content.Context;
import android.database.DataSetObserver;
-import android.os.AsyncTask;
import android.os.Build;
import android.os.Handler;
import android.view.LayoutInflater;
@@ -31,11 +30,11 @@ import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
+import android.widget.ListView;
import android.widget.TextView;
import java.io.FileInputStream;
import java.text.DateFormat;
import java.util.Date;
-import java.util.HashSet;
import java.util.Random;
import junit.framework.Assert;
@@ -46,84 +45,29 @@ import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole;
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
public class GameListAdapter extends XWListAdapter {
- private static final boolean s_isFire;
- private static Random s_random;
- static {
- s_isFire = Build.MANUFACTURER.equals( "Amazon" );
- if ( s_isFire ) {
- s_random = new Random();
- }
- }
-
private Context m_context;
+ private ListView m_list;
private LayoutInflater m_factory;
private int m_fieldID;
private Handler m_handler;
private DateFormat m_df;
private LoadItemCB m_cb;
- // Track those rows known to be good. If a rowid is not in this
- // set, assume it must be loaded. Add rowids to this set as
- // they're loaded, and remove one when when it must be redrawn.
- private HashSet m_loadedRows;
public interface LoadItemCB {
public void itemClicked( long rowid, GameSummary summary );
}
- private class LoadItemTask extends AsyncTask {
- private GameListItem m_view;
- private Context m_context;
- // private int m_id;
- public LoadItemTask( Context context, GameListItem view )
- {
- DbgUtils.logf( "Creating LoadItemTask for row %d",
- view.getRowID() );
- m_context = context;
- m_view = view;
- }
-
- @Override
- protected GameSummary doInBackground( Void... unused )
- {
- // Without this, on the Fire only the last item in the
- // list it tappable. Likely my fault, but this seems to
- // work around it.
- if ( s_isFire ) {
- try {
- int sleepTime = 500 + (s_random.nextInt() % 500);
- Thread.sleep( sleepTime );
- } catch ( Exception e ) {
- }
- }
-
- long rowid = m_view.getRowID();
- GameSummary summary = DBUtils.getSummary( m_context, rowid, 1500 );
- return summary;
- } // doInBackground
-
- @Override
- protected void onPostExecute( GameSummary summary )
- {
- setData( m_view, summary );
- setLoaded( m_view.getRowID() );
- m_view.setLoaded( true );
-
- DbgUtils.logf( "LoadItemTask for row %d finished",
- m_view.getRowID() );
- }
- } // class LoadItemTask
-
- public GameListAdapter( Context context, Handler handler, LoadItemCB cb,
- String fieldName ) {
+ public GameListAdapter( Context context, ListView list,
+ Handler handler, LoadItemCB cb, String fieldName ) {
super( DBUtils.gamesList(context).length );
m_context = context;
+ m_list = list;
m_handler = handler;
m_cb = cb;
m_factory = LayoutInflater.from( context );
m_df = DateFormat.getDateTimeInstance( DateFormat.SHORT,
DateFormat.SHORT );
- m_loadedRows = new HashSet();
m_fieldID = fieldToID( fieldName );
}
@@ -136,53 +80,29 @@ public class GameListAdapter extends XWListAdapter {
// When one needs loading it's done via an async task.
public View getView( int position, View convertView, ViewGroup parent )
{
- GameListItem result;
- boolean mustLoad = false;
- if ( null == convertView ) {
- result = (GameListItem)
- m_factory.inflate( R.layout.game_list_item, null );
- result.setRowID( DBUtils.gamesList(m_context)[position] );
- mustLoad = true;
- } else {
- result = (GameListItem)convertView;
- long rowid = result.getRowID();
- if ( isDirty(rowid) || !result.isLoaded() ) {
- mustLoad = true;
- }
- }
-
- if ( mustLoad ) {
- new LoadItemTask( m_context, result ).execute();
- }
-
+ GameListItem result = (GameListItem)
+ m_factory.inflate( R.layout.game_list_item, null );
+ result.init( m_handler, DBUtils.gamesList(m_context)[position],
+ m_fieldID, m_cb );
return result;
}
public void inval( long rowid )
{
- synchronized( m_loadedRows ) {
- m_loadedRows.remove( rowid );
+ GameListItem child = getItemFor( rowid );
+ if ( null != child ) {
+ child.forceReload();
+ } else {
+ DbgUtils.logf( "no child for rowid %d", rowid );
+ m_list.invalidate();
}
}
- private void dirtyAll()
+ public void invalName( long rowid )
{
- synchronized( m_loadedRows ) {
- m_loadedRows.clear();
- }
- }
-
- private boolean isDirty( long rowid )
- {
- synchronized( m_loadedRows ) {
- return ! m_loadedRows.contains( rowid );
- }
- }
-
- private void setLoaded( long rowid )
- {
- synchronized( m_loadedRows ) {
- m_loadedRows.add( rowid );
+ GameListItem item = getItemFor( rowid );
+ if ( null != item ) {
+ item.invalName();
}
}
@@ -201,12 +121,24 @@ public class GameListAdapter extends XWListAdapter {
+ " from %d to %d", m_fieldID, newID );
}
m_fieldID = newID;
- dirtyAll();
+ // return true so caller will do onContentChanged.
+ // There's no other way to signal GameListItem instances
+ // since we don't maintain a list of them.
changed = true;
}
return changed;
}
+ private GameListItem getItemFor( long rowid )
+ {
+ GameListItem result = null;
+ int position = positionFor( rowid );
+ if ( 0 <= position ) {
+ result = (GameListItem)m_list.getChildAt( position );
+ }
+ return result;
+ }
+
private int fieldToID( String fieldName )
{
int[] ids = {
@@ -225,106 +157,16 @@ public class GameListAdapter extends XWListAdapter {
return result;
}
- private void setData( GameListItem layout, final GameSummary summary )
+ private int positionFor( long rowid )
{
- if ( null != summary ) {
- final long rowid = layout.getRowID();
- String state = summary.summarizeState();
-
- TextView view = (TextView)layout.findViewById( R.id.game_name );
- String value = null;
- switch ( m_fieldID ) {
- case R.string.game_summary_field_empty:
- break;
- case R.string.game_summary_field_language:
- value =
- DictLangCache.getLangName( m_context,
- summary.dictLang );
- break;
- case R.string.game_summary_field_opponents:
- value = summary.playerNames();
- break;
- case R.string.game_summary_field_state:
- value = state;
+ int position = -1;
+ long[] rowids = DBUtils.gamesList( m_context );
+ for ( int ii = 0; ii < rowids.length; ++ii ) {
+ if ( rowids[ii] == rowid ) {
+ position = ii;
break;
}
-
- String name = GameUtils.getName( m_context, rowid );
-
- if ( null != value ) {
- value = m_context.getString( R.string.str_game_namef,
- name, value );
- } else {
- value = name;
- }
-
- view.setText( value );
-
- layout.setOnClickListener( new View.OnClickListener() {
- @Override
- public void onClick( View v ) {
- m_cb.itemClicked( rowid, summary );
- }
- } );
-
- LinearLayout list =
- (LinearLayout)layout.findViewById( R.id.player_list );
- boolean haveATurn = false;
- boolean haveALocalTurn = false;
- boolean[] isLocal = new boolean[1];
- for ( int ii = 0; ii < summary.nPlayers; ++ii ) {
- ExpiringLinearLayout tmp = (ExpiringLinearLayout)
- m_factory.inflate( R.layout.player_list_elem, null );
- view = (TextView)tmp.findViewById( R.id.item_name );
- view.setText( summary.summarizePlayer( ii ) );
- view = (TextView)tmp.findViewById( R.id.item_score );
- view.setText( String.format( " %d", summary.scores[ii] ) );
- boolean thisHasTurn = summary.isNextToPlay( ii, isLocal );
- if ( thisHasTurn ) {
- haveATurn = true;
- if ( isLocal[0] ) {
- haveALocalTurn = true;
- }
- }
- tmp.setPct( m_handler, thisHasTurn, isLocal[0],
- summary.lastMoveTime );
- list.addView( tmp, ii );
- }
-
- view = (TextView)layout.findViewById( R.id.state );
- view.setText( state );
- view = (TextView)layout.findViewById( R.id.modtime );
- long lastMoveTime = summary.lastMoveTime;
- lastMoveTime *= 1000;
- view.setText( m_df.format( new Date( lastMoveTime ) ) );
-
- int iconID;
- ImageView marker =
- (ImageView)layout.findViewById( R.id.msg_marker );
- CommsConnType conType = summary.conType;
- if ( CommsConnType.COMMS_CONN_RELAY == conType ) {
- iconID = R.drawable.relaygame;
- } else if ( CommsConnType.COMMS_CONN_BT == conType ) {
- iconID = android.R.drawable.stat_sys_data_bluetooth;
- } else if ( CommsConnType.COMMS_CONN_SMS == conType ) {
- iconID = android.R.drawable.sym_action_chat;
- } else {
- iconID = R.drawable.sologame;
- }
- marker.setImageResource( iconID );
-
- view = (TextView)layout.findViewById( R.id.role );
- String roleSummary = summary.summarizeRole();
- if ( null != roleSummary ) {
- view.setText( roleSummary );
- } else {
- view.setVisibility( View.GONE );
- }
-
- boolean expanded = DBUtils.getExpanded( m_context, rowid );
-
- layout.update( m_handler, expanded, summary.lastMoveTime,
- haveATurn, haveALocalTurn );
}
+ return position;
}
}
\ No newline at end of file
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListItem.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListItem.java
index fb03482d2..154ffb4c3 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListItem.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListItem.java
@@ -21,11 +21,19 @@
package org.eehouse.android.xw4;
import android.content.Context;
+import android.os.AsyncTask;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageButton;
+import android.widget.ImageView;
import android.widget.LinearLayout;
+import android.widget.TextView;
+import java.text.DateFormat;
+import java.util.Date;
+
+import org.eehouse.android.xw4.jni.GameSummary;
+import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
public class GameListItem extends LinearLayout
implements View.OnClickListener {
@@ -39,6 +47,9 @@ public class GameListItem extends LinearLayout
private long m_lastMoveTime;
private ImageButton m_expandButton;
private Handler m_handler;
+ private GameSummary m_summary;
+ private GameListAdapter.LoadItemCB m_cb;
+ private int m_fieldID;
public GameListItem( Context cx, AttributeSet as )
{
@@ -49,11 +60,31 @@ public class GameListItem extends LinearLayout
m_lastMoveTime = 0;
}
- public void update( Handler handler, boolean expanded,
- long lastMoveTime, boolean haveTurn,
- boolean haveTurnLocal )
+ public void init( Handler handler, long rowid, int fieldID,
+ GameListAdapter.LoadItemCB cb )
{
m_handler = handler;
+ m_rowid = rowid;
+ m_fieldID = fieldID;
+ m_cb = cb;
+
+ forceReload();
+ }
+
+ public void forceReload()
+ {
+ m_summary = null;
+ new LoadItemTask().execute();
+ }
+
+ public void invalName()
+ {
+ setName();
+ }
+
+ private void update( boolean expanded, long lastMoveTime, boolean haveTurn,
+ boolean haveTurnLocal )
+ {
m_expanded = expanded;
m_lastMoveTime = lastMoveTime;
m_haveTurn = haveTurn;
@@ -65,28 +96,6 @@ public class GameListItem extends LinearLayout
showHide();
}
- public void setLoaded( boolean loaded )
- {
- if ( m_loaded != loaded ) {
- m_loaded = loaded;
- // This should be enough to invalidate
- findViewById( R.id.view_unloaded )
- .setVisibility( loaded ? View.GONE : View.VISIBLE );
- findViewById( R.id.view_loaded )
- .setVisibility( loaded ? View.VISIBLE : View.GONE );
- }
- }
-
- public boolean isLoaded()
- {
- return m_loaded;
- }
-
- public void setRowID( long rowid )
- {
- m_rowid = rowid;
- }
-
public long getRowID()
{
return m_rowid;
@@ -99,6 +108,18 @@ public class GameListItem extends LinearLayout
showHide();
}
+ private void setLoaded()
+ {
+ if ( !m_loaded ) {
+ m_loaded = true;
+ // This should be enough to invalidate
+ findViewById( R.id.view_unloaded )
+ .setVisibility( m_loaded ? View.GONE : View.VISIBLE );
+ findViewById( R.id.view_loaded )
+ .setVisibility( m_loaded ? View.VISIBLE : View.GONE );
+ }
+ }
+
private void showHide()
{
m_expandButton.setImageResource( m_expanded ?
@@ -111,5 +132,137 @@ public class GameListItem extends LinearLayout
m_haveTurnLocal, m_lastMoveTime );
}
+ private String setName()
+ {
+ String state = null; // hack to avoid calling summarizeState twice
+ if ( null != m_summary ) {
+ state = m_summary.summarizeState();
+ TextView view = (TextView)findViewById( R.id.game_name );
+ String value = null;
+ switch ( m_fieldID ) {
+ case R.string.game_summary_field_empty:
+ break;
+ case R.string.game_summary_field_language:
+ value =
+ DictLangCache.getLangName( m_context,
+ m_summary.dictLang );
+ break;
+ case R.string.game_summary_field_opponents:
+ value = m_summary.playerNames();
+ break;
+ case R.string.game_summary_field_state:
+ value = state;
+ break;
+ }
+
+ if ( null != value ) {
+ String name = GameUtils.getName( m_context, m_rowid );
+ value = m_context.getString( R.string.str_game_namef,
+ name, value );
+ } else {
+ value = GameUtils.getName( m_context, m_rowid );
+ }
+
+ view.setText( value );
+ }
+ return state;
+ }
+
+ private void setData()
+ {
+ if ( null != m_summary ) {
+ TextView view;
+ String state = setName();
+
+ setOnClickListener( new View.OnClickListener() {
+ @Override
+ public void onClick( View v ) {
+ m_cb.itemClicked( m_rowid, m_summary );
+ }
+ } );
+
+ LinearLayout list =
+ (LinearLayout)findViewById( R.id.player_list );
+ list.removeAllViews();
+ boolean haveATurn = false;
+ boolean haveALocalTurn = false;
+ boolean[] isLocal = new boolean[1];
+ for ( int ii = 0; ii < m_summary.nPlayers; ++ii ) {
+ ExpiringLinearLayout tmp = (ExpiringLinearLayout)
+ Utils.inflate( m_context, R.layout.player_list_elem );
+ view = (TextView)tmp.findViewById( R.id.item_name );
+ view.setText( m_summary.summarizePlayer( ii ) );
+ view = (TextView)tmp.findViewById( R.id.item_score );
+ view.setText( String.format( " %d", m_summary.scores[ii] ) );
+ boolean thisHasTurn = m_summary.isNextToPlay( ii, isLocal );
+ if ( thisHasTurn ) {
+ haveATurn = true;
+ if ( isLocal[0] ) {
+ haveALocalTurn = true;
+ }
+ }
+ tmp.setPct( m_handler, thisHasTurn, isLocal[0],
+ m_summary.lastMoveTime );
+ list.addView( tmp, ii );
+ }
+
+ view = (TextView)findViewById( R.id.state );
+ view.setText( state );
+ view = (TextView)findViewById( R.id.modtime );
+ long lastMoveTime = m_summary.lastMoveTime;
+ lastMoveTime *= 1000;
+
+ DateFormat df = DateFormat.getDateTimeInstance( DateFormat.SHORT,
+ DateFormat.SHORT );
+ view.setText( df.format( new Date( lastMoveTime ) ) );
+
+ int iconID;
+ ImageView marker =
+ (ImageView)findViewById( R.id.msg_marker );
+ CommsConnType conType = m_summary.conType;
+ if ( CommsConnType.COMMS_CONN_RELAY == conType ) {
+ iconID = R.drawable.relaygame;
+ } else if ( CommsConnType.COMMS_CONN_BT == conType ) {
+ iconID = android.R.drawable.stat_sys_data_bluetooth;
+ } else if ( CommsConnType.COMMS_CONN_SMS == conType ) {
+ iconID = android.R.drawable.sym_action_chat;
+ } else {
+ iconID = R.drawable.sologame;
+ }
+ marker.setImageResource( iconID );
+
+ view = (TextView)findViewById( R.id.role );
+ String roleSummary = m_summary.summarizeRole();
+ if ( null != roleSummary ) {
+ view.setText( roleSummary );
+ } else {
+ view.setVisibility( View.GONE );
+ }
+
+ boolean expanded = DBUtils.getExpanded( m_context, m_rowid );
+
+ update( expanded, m_summary.lastMoveTime, haveATurn,
+ haveALocalTurn );
+ }
+ }
+
+ private class LoadItemTask extends AsyncTask {
+ @Override
+ protected GameSummary doInBackground( Void... unused )
+ {
+ return DBUtils.getSummary( m_context, m_rowid, 1500 );
+ } // doInBackground
+
+ @Override
+ protected void onPostExecute( GameSummary summary )
+ {
+ m_summary = summary;
+ setData();
+ // setLoaded( m_view.getRowID() );
+ setLoaded();
+
+ DbgUtils.logf( "LoadItemTask for row %d finished", m_rowid );
+ }
+ } // class LoadItemTask
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
index 99697680b..301f153da 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
@@ -200,8 +200,7 @@ public class GamesList extends XWListActivity
public void onClick( DialogInterface dlg, int item ) {
String name = namerView.getName();
DBUtils.setName( GamesList.this, m_rowid, name );
- m_adapter.inval( m_rowid );
- onContentChanged();
+ m_adapter.invalName( m_rowid );
}
};
dialog = new AlertDialog.Builder( this )
@@ -283,7 +282,8 @@ public class GamesList extends XWListActivity
});
String field = CommonPrefs.getSummaryField( this );
- m_adapter = new GameListAdapter( this, new Handler(), this, field );
+ m_adapter = new GameListAdapter( this, getListView(), new Handler(),
+ this, field );
setListAdapter( m_adapter );
NetUtils.informOfDeaths( this );
@@ -381,12 +381,15 @@ public class GamesList extends XWListActivity
}
// DBUtils.DBChangeListener interface
- public void gameSaved( final long rowid )
+ public void gameSaved( final long rowid, final boolean countChanged )
{
post( new Runnable() {
public void run() {
- m_adapter.inval( rowid );
- onContentChanged();
+ if ( countChanged ) {
+ onContentChanged();
+ } else {
+ m_adapter.inval( rowid );
+ }
}
} );
}
@@ -457,7 +460,6 @@ public class GamesList extends XWListActivity
long[] games = DBUtils.gamesList( this );
for ( int ii = games.length - 1; ii >= 0; --ii ) {
GameUtils.deleteGame( this, games[ii], ii == 0 );
- m_adapter.inval( games[ii] );
}
break;
case SYNC_MENU_ACTION:
@@ -738,7 +740,6 @@ public class GamesList extends XWListActivity
}
}
}
- onContentChanged();
}
}
@@ -846,7 +847,9 @@ public class GamesList extends XWListActivity
{
String newField = CommonPrefs.getSummaryField( this );
if ( m_adapter.setField( newField ) ) {
- onContentChanged();
+ // The adapter should be able to decide whether full
+ // content change is required. PENDING
+ onContentChanged();
}
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListAdapter.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListAdapter.java
index 52306419b..decc6fde6 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListAdapter.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListAdapter.java
@@ -42,13 +42,13 @@ public abstract class XWListAdapter implements ListAdapter {
public boolean isEnabled( int position ) { return true; }
public int getCount() { return m_count; }
public Object getItem( int position ) { return null; }
- public long getItemId(int position) { return position; }
+ public long getItemId( int position ) { return position; }
public int getItemViewType( int position ) {
return ListAdapter.IGNORE_ITEM_VIEW_TYPE;
}
public int getViewTypeCount() { return 1; }
public boolean hasStableIds() { return true; }
public boolean isEmpty() { return getCount() == 0; }
- public void registerDataSetObserver(DataSetObserver observer) {}
- public void unregisterDataSetObserver(DataSetObserver observer) {}
+ public void registerDataSetObserver( DataSetObserver observer ) {}
+ public void unregisterDataSetObserver( DataSetObserver observer ) {}
}
\ No newline at end of file
From f599ca8be42b9aed181e0bb703b3d8dcdc5ec33e Mon Sep 17 00:00:00 2001
From: Eric House
Date: Mon, 10 Dec 2012 07:54:42 -0800
Subject: [PATCH 117/146] make tiles square based on rowid so people can see
both
---
.../src/org/eehouse/android/xw4/BoardActivity.java | 1 +
.../XWords4/src/org/eehouse/android/xw4/BoardView.java | 10 +++++++---
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
index e638df480..c4003c5fa 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
@@ -509,6 +509,7 @@ public class BoardActivity extends XWActivity
Intent intent = getIntent();
m_rowid = intent.getLongExtra( GameUtils.INTENT_KEY_ROWID, -1 );
+ m_view.setRowID( m_rowid );
m_haveInvited = intent.getBooleanExtra( GameUtils.INVITED, false );
m_overNotShown = true;
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardView.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardView.java
index d05909c99..9c4b62c67 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardView.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardView.java
@@ -53,8 +53,6 @@ public class BoardView extends View implements DrawCtx, BoardHandler,
private static final int PINCH_THRESHOLD = 40;
private static final int SCORE_HT_DROP = 2;
private static final boolean DEBUG_DRAWFRAMES = false;
- // this can be a preference
- private static final boolean MAKETILESSQUARE = true;
private Context m_context;
private Paint m_drawPaint;
@@ -77,6 +75,7 @@ public class BoardView extends View implements DrawCtx, BoardHandler,
private boolean m_blackArrow;
private boolean m_inTrade = false;
private boolean m_hasSmallScreen;
+ private long m_rowid;
// m_backgroundUsed: alpha not set ensures inequality
private int m_backgroundUsed = 0x00000000;
private boolean m_darkOnLight;
@@ -239,6 +238,11 @@ public class BoardView extends View implements DrawCtx, BoardHandler,
return true; // required to get subsequent events
}
+ public void setRowID( long rowid )
+ {
+ m_rowid = rowid;
+ }
+
// private void printMode( String comment, int mode )
// {
// comment += ": ";
@@ -384,7 +388,7 @@ public class BoardView extends View implements DrawCtx, BoardHandler,
scoreHt += heightLeft;
trayHt += heightLeft * 2;
- if ( MAKETILESSQUARE && trayHt > width / 7 ) {
+ if ( (1 == (m_rowid % 2)) && trayHt > width / 7 ) {
trayHt = width / 7;
}
heightUsed = trayHt + scoreHt + ((nCells - nToScroll) * cellSize);
From 877225f59dc3b6248a6a4190c14886a93079395d Mon Sep 17 00:00:00 2001
From: Eric House
Date: Mon, 10 Dec 2012 18:20:44 -0800
Subject: [PATCH 118/146] rename interface; no code change
---
.../src/org/eehouse/android/xw4/BTInviteActivity.java | 2 +-
.../XWords4/src/org/eehouse/android/xw4/BTService.java | 2 +-
.../XWords4/src/org/eehouse/android/xw4/BoardActivity.java | 2 +-
.../XWords4/src/org/eehouse/android/xw4/GamesList.java | 2 +-
.../XWords4/src/org/eehouse/android/xw4/MultiService.java | 6 +++---
.../src/org/eehouse/android/xw4/NewGameActivity.java | 4 ++--
.../XWords4/src/org/eehouse/android/xw4/SMSService.java | 2 +-
.../XWords4/src/org/eehouse/android/xw4/XWActivity.java | 4 ++--
.../XWords4/src/org/eehouse/android/xw4/XWListActivity.java | 4 ++--
9 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BTInviteActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BTInviteActivity.java
index fcfcbd51a..bcc4c325c 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BTInviteActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BTInviteActivity.java
@@ -65,7 +65,7 @@ public class BTInviteActivity extends InviteActivity
BTService.clearDevices( this, null ); // will return names
}
- // BTService.BTEventListener interface
+ // MultiService.MultiEventListener interface
@Override
public void eventOccurred( MultiService.MultiEvent event, final Object ... args )
{
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BTService.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BTService.java
index f62100c4e..4d6f8fd6d 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BTService.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BTService.java
@@ -147,7 +147,7 @@ public class BTService extends Service {
}
}
- public static void setListener( MultiService.BTEventListener li )
+ public static void setListener( MultiService.MultiEventListener li )
{
if ( XWApp.BTSUPPORTED ) {
if ( null == s_srcMgr ) {
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
index c4003c5fa..f8a5f802c 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
@@ -924,7 +924,7 @@ public class BoardActivity extends XWActivity
}
//////////////////////////////////////////////////
- // BTService.BTEventListener interface
+ // MultiService.MultiEventListener interface
//////////////////////////////////////////////////
@Override
@SuppressWarnings("fallthrough")
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
index 301f153da..306a7a4aa 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
@@ -419,7 +419,7 @@ public class GamesList extends XWListActivity
}
}
- // BTService.BTEventListener interface
+ // BTService.MultiEventListener interface
@Override
public void eventOccurred( MultiService.MultiEvent event,
final Object ... args )
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/MultiService.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/MultiService.java
index 4e4d21686..5d2a776eb 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/MultiService.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/MultiService.java
@@ -42,7 +42,7 @@ public class MultiService {
public static final int OWNER_SMS = 1;
public static final int OWNER_RELAY = 2;
- private BTEventListener m_li;
+ private MultiEventListener m_li;
public enum MultiEvent { BAD_PROTO
, BT_ENABLED
@@ -64,14 +64,14 @@ public class MultiService {
, SMS_SEND_FAILED_NORADIO
};
- public interface BTEventListener {
+ public interface MultiEventListener {
public void eventOccurred( MultiEvent event, Object ... args );
}
// public interface MultiEventSrc {
// public void setBTEventListener( BTEventListener li );
// }
- public void setListener( BTEventListener li )
+ public void setListener( MultiEventListener li )
{
synchronized( this ) {
m_li = li;
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NewGameActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NewGameActivity.java
index 85bbccd63..d1b90148a 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NewGameActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NewGameActivity.java
@@ -256,7 +256,7 @@ public class NewGameActivity extends XWActivity {
return dialog;
}
- // BTService.BTEventListener interface
+ // MultiService.MultiEventListener interface
@Override
public void eventOccurred( MultiService.MultiEvent event,
final Object ... args )
@@ -299,7 +299,7 @@ public class NewGameActivity extends XWActivity {
super.eventOccurred( event, args );
break;
}
- } // BTService.BTEventListener.eventOccurred
+ } // MultiService.MultiEventListener.eventOccurred
private void makeNewGame( boolean networked, boolean launch )
{
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java
index 6734e1220..be0a95ef2 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java
@@ -189,7 +189,7 @@ public class SMSService extends Service {
return result;
}
- public static void setListener( MultiService.BTEventListener li )
+ public static void setListener( MultiService.MultiEventListener li )
{
if ( XWApp.SMSSUPPORTED ) {
if ( null == s_srcMgr ) {
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWActivity.java
index 18670d379..71e8a922d 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWActivity.java
@@ -31,7 +31,7 @@ import android.widget.TextView;
import junit.framework.Assert;
public class XWActivity extends Activity
- implements DlgDelegate.DlgClickNotify, MultiService.BTEventListener {
+ implements DlgDelegate.DlgClickNotify, MultiService.MultiEventListener {
private DlgDelegate m_delegate;
@@ -192,7 +192,7 @@ public class XWActivity extends Activity
Assert.fail();
}
- // BTService.BTEventListener interface
+ // BTService.MultiEventListener interface
public void eventOccurred( MultiService.MultiEvent event,
final Object ... args )
{
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListActivity.java
index 9f10da3d4..927b73f78 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListActivity.java
@@ -28,7 +28,7 @@ import android.os.Bundle;
import junit.framework.Assert;
public class XWListActivity extends ListActivity
- implements DlgDelegate.DlgClickNotify, MultiService.BTEventListener {
+ implements DlgDelegate.DlgClickNotify, MultiService.MultiEventListener {
private DlgDelegate m_delegate;
@@ -193,7 +193,7 @@ public class XWListActivity extends ListActivity
m_delegate.launchLookup( words, lang, forceList );
}
- // BTService.BTEventListener interface
+ // MultiService.MultiEventListener interface
public void eventOccurred( MultiService.MultiEvent event,
final Object ... args )
{
From b2bd6ce662b382d8c59f8e95342733d42ac50ec9 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Tue, 11 Dec 2012 07:25:43 -0800
Subject: [PATCH 119/146] add and use preference for square rack tiles,
removing code that alternated for testing purposes.
---
xwords4/android/XWords4/res/values/common_rsrc.xml | 1 +
xwords4/android/XWords4/res/values/strings.xml | 4 ++++
xwords4/android/XWords4/res/xml/xwprefs.xml | 5 +++++
.../src/org/eehouse/android/xw4/BoardActivity.java | 1 -
.../XWords4/src/org/eehouse/android/xw4/BoardView.java | 9 ++-------
.../XWords4/src/org/eehouse/android/xw4/XWPrefs.java | 5 +++++
6 files changed, 17 insertions(+), 8 deletions(-)
diff --git a/xwords4/android/XWords4/res/values/common_rsrc.xml b/xwords4/android/XWords4/res/values/common_rsrc.xml
index 860b43b11..759d74e00 100644
--- a/xwords4/android/XWords4/res/values/common_rsrc.xml
+++ b/xwords4/android/XWords4/res/values/common_rsrc.xml
@@ -6,6 +6,7 @@
key_color_tiles
key_show_arrow
+ key_square_tiles
key_explain_robot
key_skip_confirm
key_sort_tiles
diff --git a/xwords4/android/XWords4/res/values/strings.xml b/xwords4/android/XWords4/res/values/strings.xml
index 55f904e56..cdd796f20 100644
--- a/xwords4/android/XWords4/res/values/strings.xml
+++ b/xwords4/android/XWords4/res/values/strings.xml
@@ -2135,4 +2135,8 @@
game with the same players and parameters as the one that
just ended. -->
Rematch
+
+ Square rack tiles
+ Even if they can be taller
+
diff --git a/xwords4/android/XWords4/res/xml/xwprefs.xml b/xwords4/android/XWords4/res/xml/xwprefs.xml
index 86fdece79..2cb350166 100644
--- a/xwords4/android/XWords4/res/xml/xwprefs.xml
+++ b/xwords4/android/XWords4/res/xml/xwprefs.xml
@@ -132,6 +132,11 @@
android:summary="@string/show_arrow_summary"
android:defaultValue="true"
/>
+
width / 7 ) {
+ if ( XWPrefs.getSquareTiles( m_context )
+ && trayHt > (width / 7) ) {
trayHt = width / 7;
}
heightUsed = trayHt + scoreHt + ((nCells - nToScroll) * cellSize);
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWPrefs.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWPrefs.java
index dce8adae8..b966a051e 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWPrefs.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWPrefs.java
@@ -83,6 +83,11 @@ public class XWPrefs {
return getPrefsBoolean( context, R.string.key_ringer_zoom, false );
}
+ public static boolean getSquareTiles( Context context )
+ {
+ return getPrefsBoolean( context, R.string.key_square_tiles, false );
+ }
+
public static int getDefaultPlayerMinutes( Context context )
{
String value =
From 7246ae28c697043c1b6475610c9546f1de97aab1 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Tue, 11 Dec 2012 19:09:33 -0800
Subject: [PATCH 120/146] clear the cache after loading a new DB so will redraw
correctly in list
---
xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
index 8deebeeaa..679b62a80 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
@@ -924,6 +924,7 @@ public class DBUtils {
public static void loadDB( Context context )
{
+ clearRowIDsCache();
copyGameDB( context, false );
}
From 01d17fe0c50783bfb3033d420e5466099a4b7f5c Mon Sep 17 00:00:00 2001
From: Eric House
Date: Tue, 11 Dec 2012 19:10:05 -0800
Subject: [PATCH 121/146] redraw full list after resetting a game in case
position changes
---
.../android/XWords4/src/org/eehouse/android/xw4/GamesList.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
index 306a7a4aa..833c4eac4 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
@@ -452,6 +452,7 @@ public class GamesList extends XWListActivity
break;
case RESET_GAME_ACTION:
GameUtils.resetGame( this, m_rowid );
+ onContentChanged(); // required because position may change
break;
case DELETE_GAME_ACTION:
GameUtils.deleteGame( this, m_rowid, true );
From 575d5e97453693041825686a6acfcb6838a14839 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Tue, 11 Dec 2012 19:11:23 -0800
Subject: [PATCH 122/146] reduce time we'll wait for a summary to unlock when
loading it for games list.
---
.../XWords4/src/org/eehouse/android/xw4/GameListItem.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListItem.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListItem.java
index 154ffb4c3..89f9e4b7a 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListItem.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListItem.java
@@ -250,7 +250,7 @@ public class GameListItem extends LinearLayout
@Override
protected GameSummary doInBackground( Void... unused )
{
- return DBUtils.getSummary( m_context, m_rowid, 1500 );
+ return DBUtils.getSummary( m_context, m_rowid, 150 );
} // doInBackground
@Override
From eee954e705101556a414571dbe7b8f0419e42c4a Mon Sep 17 00:00:00 2001
From: Eric House
Date: Tue, 11 Dec 2012 19:15:15 -0800
Subject: [PATCH 123/146] list changes for next release
---
xwords4/android/XWords4/res/raw/changes | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/xwords4/android/XWords4/res/raw/changes b/xwords4/android/XWords4/res/raw/changes
index c1165a0bd..d87b350f7 100644
--- a/xwords4/android/XWords4/res/raw/changes
+++ b/xwords4/android/XWords4/res/raw/changes
@@ -9,11 +9,17 @@
New with this release
+ - Include attachment in email invites for devices that don't dispatch
+ URLs correctly (e.g. some by HTC)
+ - Fix flickering in main screen (games list)
+ - Add option, off by default, to keep rack tiles square even when
+ the screen is large enough that they can be taller
+ - Show final scores alert whenever a finished game is opened -- to
+ make it more clear that it's finished
Next up
- - One more idea for improving invitations
- Allow grouping of games in collapsible user-defined categores: "Games with
Kati", "Finished games", etc.
From 69f868722f54e754a1ac2a8da9282cb831e1192c Mon Sep 17 00:00:00 2001
From: Eric House
Date: Wed, 12 Dec 2012 06:41:56 -0800
Subject: [PATCH 124/146] cancel any notification for game when resetting it
---
.../android/XWords4/src/org/eehouse/android/xw4/GameUtils.java | 2 ++
1 file changed, 2 insertions(+)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
index 420819c46..a5c442cc1 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
@@ -246,6 +246,8 @@ public class GameUtils {
tellDied( context, lock, true );
resetGame( context, lock, lock, false );
lock.unlock();
+
+ Utils.cancelNotification( context, (int)rowidIn );
}
private static GameSummary summarizeAndClose( Context context,
From db8364c28551c19bbc5a0481f4ece10333417342 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Wed, 12 Dec 2012 06:43:18 -0800
Subject: [PATCH 125/146] return empty array rather than null when query
succeeds but produces no result.
---
.../XWords4/src/org/eehouse/android/xw4/DBUtils.java | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
index 679b62a80..b584fcc8e 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
@@ -451,10 +451,8 @@ public class DBUtils {
String selection = DBHelper.RELAYID + "='" + relayID + "'";
Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
selection, null, null, null, null );
+ result = new long[cursor.getCount()];
for ( int ii = 0; cursor.moveToNext(); ++ii ) {
- if ( null == result ) {
- result = new long[cursor.getCount()];
- }
result[ii] = cursor.getLong( cursor.getColumnIndex(ROW_ID) );
}
cursor.close();
@@ -473,11 +471,8 @@ public class DBUtils {
String selection = String.format( DBHelper.GAMEID + "=%d", gameID );
Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
selection, null, null, null, null );
-
+ result = new long[cursor.getCount()];
for ( int ii = 0; cursor.moveToNext(); ++ii ) {
- if ( null == result ) {
- result = new long[cursor.getCount()];
- }
result[ii] = cursor.getLong( cursor.getColumnIndex(ROW_ID) );
}
cursor.close();
From b71046e5aac08f1f920c5245b4c958c187a7327d Mon Sep 17 00:00:00 2001
From: Eric House
Date: Wed, 12 Dec 2012 07:13:25 -0800
Subject: [PATCH 126/146] lock, rather than tryLock, game when feeding it
messages. Otherwise messages are dropped e.g. when UI's loading a summary in
GameListItem.
---
.../org/eehouse/android/xw4/GameUtils.java | 48 +++++++++----------
1 file changed, 24 insertions(+), 24 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
index a5c442cc1..a1837bd7a 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
@@ -713,35 +713,35 @@ public class GameUtils {
{
boolean draw = false;
Assert.assertTrue( -1 != rowid );
- GameLock lock = new GameLock( rowid, true );
- if ( lock.tryLock() ) {
- CurGameInfo gi = new CurGameInfo( context );
- FeedUtilsImpl feedImpl = new FeedUtilsImpl( context, rowid );
- int gamePtr = loadMakeGame( context, gi, feedImpl, sink, lock );
- if ( 0 != gamePtr ) {
- XwJNI.comms_resendAll( gamePtr, false, false );
+ GameLock lock = new GameLock( rowid, true ).lock();
- if ( null != msgs ) {
- for ( byte[] msg : msgs ) {
- draw = XwJNI.game_receiveMessage( gamePtr, msg, ret )
- || draw;
- }
- }
- XwJNI.comms_ackAny( gamePtr );
+ CurGameInfo gi = new CurGameInfo( context );
+ FeedUtilsImpl feedImpl = new FeedUtilsImpl( context, rowid );
+ int gamePtr = loadMakeGame( context, gi, feedImpl, sink, lock );
+ if ( 0 != gamePtr ) {
+ XwJNI.comms_resendAll( gamePtr, false, false );
- // update gi to reflect changes due to messages
- XwJNI.game_getGi( gamePtr, gi );
- saveGame( context, gamePtr, gi, lock, false );
- summarizeAndClose( context, lock, gamePtr, gi, feedImpl );
-
- int flags = setFromFeedImpl( feedImpl );
- if ( GameSummary.MSG_FLAGS_NONE != flags ) {
- draw = true;
- DBUtils.setMsgFlags( rowid, flags );
+ if ( null != msgs ) {
+ for ( byte[] msg : msgs ) {
+ draw = XwJNI.game_receiveMessage( gamePtr, msg, ret )
+ || draw;
}
}
- lock.unlock();
+ XwJNI.comms_ackAny( gamePtr );
+
+ // update gi to reflect changes due to messages
+ XwJNI.game_getGi( gamePtr, gi );
+ saveGame( context, gamePtr, gi, lock, false );
+ summarizeAndClose( context, lock, gamePtr, gi, feedImpl );
+
+ int flags = setFromFeedImpl( feedImpl );
+ if ( GameSummary.MSG_FLAGS_NONE != flags ) {
+ draw = true;
+ DBUtils.setMsgFlags( rowid, flags );
+ }
}
+ lock.unlock();
+
return draw;
} // feedMessages
From 91ac04b8965825778d697bf3d4b9fa5f9b519dce Mon Sep 17 00:00:00 2001
From: Eric House
Date: Thu, 13 Dec 2012 06:32:57 -0800
Subject: [PATCH 127/146] remove logging
---
.../XWords4/src/org/eehouse/android/xw4/GameListItem.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListItem.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListItem.java
index 89f9e4b7a..d5d727b08 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListItem.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListItem.java
@@ -261,7 +261,7 @@ public class GameListItem extends LinearLayout
// setLoaded( m_view.getRowID() );
setLoaded();
- DbgUtils.logf( "LoadItemTask for row %d finished", m_rowid );
+ // DbgUtils.logf( "LoadItemTask for row %d finished", m_rowid );
}
} // class LoadItemTask
From 6060d5e8bdd04e497c58cf932b9329864a3a9fdf Mon Sep 17 00:00:00 2001
From: Eric House
Date: Thu, 13 Dec 2012 06:57:12 -0800
Subject: [PATCH 128/146] Fix hangs when receiving relay messages in background
for open game by adding a static feedMessages method like the one used by SMS
and BT games. For that to work, rowid and relayid need to be fetched and
tracked together -- so do that in RelayService.
---
.../eehouse/android/xw4/BoardActivity.java | 22 ++++
.../src/org/eehouse/android/xw4/DBUtils.java | 27 +++--
.../org/eehouse/android/xw4/DlgDelegate.java | 2 +-
.../org/eehouse/android/xw4/GameUtils.java | 102 +++++++++---------
.../src/org/eehouse/android/xw4/NetUtils.java | 16 ++-
.../org/eehouse/android/xw4/RelayService.java | 47 ++++----
.../src/org/eehouse/android/xw4/XWApp.java | 4 +-
7 files changed, 129 insertions(+), 91 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
index 396270e30..ff5f5a104 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
@@ -189,6 +189,27 @@ public class BoardActivity extends XWActivity
return delivered;
}
+ public static boolean feedMessages( long rowid, byte[][] msgs )
+ {
+ boolean delivered = false;
+ Assert.assertNotNull( msgs );
+ synchronized( s_thisLocker ) {
+ if ( null != s_this ) {
+ Assert.assertNotNull( s_this.m_gi );
+ Assert.assertNotNull( s_this.m_gameLock );
+ Assert.assertNotNull( s_this.m_jniThread );
+ if ( rowid == s_this.m_rowid ) {
+ delivered = true; // even if no messages!
+ for ( byte[] msg : msgs ) {
+ s_this.m_jniThread.handle( JNICmd.CMD_RECEIVE, msg,
+ null );
+ }
+ }
+ }
+ }
+ return delivered;
+ }
+
private static void setThis( BoardActivity self )
{
synchronized( s_thisLocker ) {
@@ -509,6 +530,7 @@ public class BoardActivity extends XWActivity
Intent intent = getIntent();
m_rowid = intent.getLongExtra( GameUtils.INTENT_KEY_ROWID, -1 );
+ DbgUtils.logf( "BoardActivity: opening rowid %d", m_rowid );
m_haveInvited = intent.getBooleanExtra( GameUtils.INVITED, false );
m_overNotShown = true;
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
index b584fcc8e..cc6529755 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
@@ -573,7 +573,7 @@ public class DBUtils {
return result;
}
- public static String[] getRelayIDs( Context context, boolean noMsgs )
+ public static String[] getRelayIDs( Context context, long[][] rowIDs )
{
String[] result = null;
initDB( context );
@@ -581,26 +581,31 @@ public class DBUtils {
synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
- String[] columns = { DBHelper.RELAYID };
+ String[] columns = { ROW_ID, DBHelper.RELAYID };
String selection = DBHelper.RELAYID + " NOT null";
- if ( noMsgs ) {
- selection += " AND NOT " + DBHelper.HASMSGS;
- }
Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
selection, null, null, null, null );
+ int count = cursor.getCount();
+ if ( 0 < count ) {
+ result = new String[count];
+ if ( null != rowIDs ) {
+ rowIDs[0] = new long[count];
+ }
- while ( cursor.moveToNext() ) {
- ids.add( cursor.getString( cursor.
- getColumnIndex(DBHelper.RELAYID)) );
+ int idIndex = cursor.getColumnIndex(DBHelper.RELAYID);
+ int rowIndex = cursor.getColumnIndex(ROW_ID);
+ for ( int ii = 0; cursor.moveToNext(); ++ii ) {
+ result[ii] = cursor.getString( idIndex );
+ if ( null != rowIDs ) {
+ rowIDs[0][ii] = cursor.getLong( rowIndex );
+ }
+ }
}
cursor.close();
db.close();
}
- if ( 0 < ids.size() ) {
- result = ids.toArray( new String[ids.size()] );
- }
return result;
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DlgDelegate.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DlgDelegate.java
index b0e642bf1..05ace973a 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DlgDelegate.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DlgDelegate.java
@@ -242,7 +242,7 @@ public class DlgDelegate {
public void doSyncMenuitem()
{
- if ( null == DBUtils.getRelayIDs( m_activity, false ) ) {
+ if ( null == DBUtils.getRelayIDs( m_activity, null ) ) {
showOKOnlyDialog( R.string.no_games_to_refresh );
} else {
RelayReceiver.RestartTimer( m_activity, true );
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
index a1837bd7a..e9cc53ce7 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
@@ -111,16 +111,21 @@ public class GameUtils {
final long assertTime = 2000;
Assert.assertTrue( maxMillis < assertTime );
long sleptTime = 0;
- // DbgUtils.logf( "GameLock.lock(%s)", m_path );
- // Utils.printStack();
+
+ if ( XWApp.DEBUG_LOCKS ) {
+ DbgUtils.logf( "lock %H (rowid:%d, maxMillis=%d)",
+ this, m_rowid, maxMillis );
+ }
+
for ( ; ; ) {
if ( tryLock() ) {
result = this;
break;
}
if ( XWApp.DEBUG_LOCKS ) {
- DbgUtils.logf( "GameLock.lock() %H failed; sleeping", this );
- DbgUtils.printStack();
+ DbgUtils.logf( "GameLock.lock() %H failed (rowid:%d); sleeping",
+ this, m_rowid );
+ // DbgUtils.printStack();
}
try {
Thread.sleep( 25 ); // milliseconds
@@ -130,12 +135,17 @@ public class GameUtils {
break;
}
+ if ( XWApp.DEBUG_LOCKS ) {
+ DbgUtils.logf( "GameLock.lock() %H awake; "
+ + "sleptTime now %d millis", this, sleptTime );
+ }
+
if ( 0 < maxMillis && sleptTime >= maxMillis ) {
break;
} else if ( sleptTime >= assertTime ) {
if ( XWApp.DEBUG_LOCKS ) {
- DbgUtils.logf( "lock %H overlocked. lock holding stack:",
- this );
+ DbgUtils.logf( "lock %H overlocked waiting for rowid:%d. "
+ + "lock holding stack:", m_rowid, this );
DbgUtils.printStack( m_lockTrace );
DbgUtils.logf( "lock %H seeking stack:", this );
DbgUtils.printStack();
@@ -158,8 +168,12 @@ public class GameUtils {
Assert.assertTrue( !m_isForWrite );
}
--m_lockCount;
+
+ if ( XWApp.DEBUG_LOCKS ) {
+ DbgUtils.logf( "GameLock.unlock: this: %H (rowid:%d) "
+ + "unlocked", this, m_rowid );
+ }
}
- // DbgUtils.logf( "GameLock.unlock(%s) done", m_path );
}
public long getRowid()
@@ -707,41 +721,46 @@ public class GameUtils {
}
}
- private static boolean feedMessages( Context context, long rowid,
- byte[][] msgs, CommsAddrRec ret,
- MultiMsgSink sink )
+ public static boolean feedMessages( Context context, long rowid,
+ byte[][] msgs, CommsAddrRec ret,
+ MultiMsgSink sink )
{
boolean draw = false;
Assert.assertTrue( -1 != rowid );
- GameLock lock = new GameLock( rowid, true ).lock();
+ if ( null != msgs ) {
+ // timed lock: If a game is opened by BoardActivity just
+ // as we're trying to deliver this message to it it'll
+ // have the lock and we'll never get it. Better to drop
+ // the message than fire the hung-lock assert. Messages
+ // belong in local pre-delivery storage anyway.
+ GameLock lock = new GameLock( rowid, true ).lock( 150 );
+ if ( null != lock ) {
+ CurGameInfo gi = new CurGameInfo( context );
+ FeedUtilsImpl feedImpl = new FeedUtilsImpl( context, rowid );
+ int gamePtr = loadMakeGame( context, gi, feedImpl, sink, lock );
+ if ( 0 != gamePtr ) {
+ XwJNI.comms_resendAll( gamePtr, false, false );
- CurGameInfo gi = new CurGameInfo( context );
- FeedUtilsImpl feedImpl = new FeedUtilsImpl( context, rowid );
- int gamePtr = loadMakeGame( context, gi, feedImpl, sink, lock );
- if ( 0 != gamePtr ) {
- XwJNI.comms_resendAll( gamePtr, false, false );
+ for ( byte[] msg : msgs ) {
+ draw = XwJNI.game_receiveMessage( gamePtr, msg, ret )
+ || draw;
+ }
+ XwJNI.comms_ackAny( gamePtr );
- if ( null != msgs ) {
- for ( byte[] msg : msgs ) {
- draw = XwJNI.game_receiveMessage( gamePtr, msg, ret )
- || draw;
+ // update gi to reflect changes due to messages
+ XwJNI.game_getGi( gamePtr, gi );
+ saveGame( context, gamePtr, gi, lock, false );
+ summarizeAndClose( context, lock, gamePtr, gi, feedImpl );
+
+ int flags = setFromFeedImpl( feedImpl );
+ if ( GameSummary.MSG_FLAGS_NONE != flags ) {
+ draw = true;
+ DBUtils.setMsgFlags( rowid, flags );
+ }
}
- }
- XwJNI.comms_ackAny( gamePtr );
-
- // update gi to reflect changes due to messages
- XwJNI.game_getGi( gamePtr, gi );
- saveGame( context, gamePtr, gi, lock, false );
- summarizeAndClose( context, lock, gamePtr, gi, feedImpl );
-
- int flags = setFromFeedImpl( feedImpl );
- if ( GameSummary.MSG_FLAGS_NONE != flags ) {
- draw = true;
- DBUtils.setMsgFlags( rowid, flags );
+ lock.unlock();
}
}
- lock.unlock();
-
return draw;
} // feedMessages
@@ -754,21 +773,6 @@ public class GameUtils {
return feedMessages( context, rowid, msgs, ret, sink );
}
- // Current assumption: this is the relay case where return address
- // can be null.
- public static boolean feedMessages( Context context, String relayID,
- byte[][] msgs, MultiMsgSink sink )
- {
- boolean draw = false;
- long[] rowids = DBUtils.getRowIDsFor( context, relayID );
- if ( null != rowids ) {
- for ( long rowid : rowids ) {
- draw = feedMessages( context, rowid, msgs, null, sink ) || draw;
- }
- }
- return draw;
- }
-
// This *must* involve a reset if the language is changing!!!
// Which isn't possible right now, so make sure the old and new
// dict have the same langauge code.
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetUtils.java
index 4f900a76d..75d3d11b0 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetUtils.java
@@ -130,8 +130,7 @@ public class NetUtils {
}
}
- public static byte[][][] queryRelay( Context context, String[] ids,
- int nBytes )
+ public static byte[][][] queryRelay( Context context, String[] ids )
{
byte[][][] msgs = null;
try {
@@ -141,6 +140,7 @@ public class NetUtils {
new DataOutputStream( socket.getOutputStream() );
// total packet size
+ int nBytes = sumStrings( ids );
outStream.writeShort( 2 + nBytes + ids.length + 1 );
outStream.writeByte( NetUtils.PROTOCOL_VERSION );
@@ -263,4 +263,16 @@ public class NetUtils {
DbgUtils.logf( "sendToRelay: null msgs" );
}
} // sendToRelay
+
+ private static int sumStrings( final String[] strs )
+ {
+ int len = 0;
+ if ( null != strs ) {
+ for ( String str : strs ) {
+ len += str.length();
+ }
+ }
+ return len;
+ }
+
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayService.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayService.java
index c312a8fc8..5da48cd30 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayService.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayService.java
@@ -74,45 +74,40 @@ public class RelayService extends Service {
}
}
}
-
- private String[] collectIDs( int[] nBytes )
- {
- String[] ids = DBUtils.getRelayIDs( this, false );
- int len = 0;
- if ( null != ids ) {
- for ( String id : ids ) {
- len += id.length();
- }
- }
- nBytes[0] = len;
- return ids;
- }
private void fetchAndProcess()
{
- int[] nBytes = new int[1];
- String[] ids = collectIDs( nBytes );
- if ( null != ids && 0 < ids.length ) {
- RelayMsgSink sink = new RelayMsgSink();
- byte[][][] msgs =
- NetUtils.queryRelay( this, ids, nBytes[0] );
+ long[][] rowIDss = new long[1][];
+ String[] relayIDs = DBUtils.getRelayIDs( this, rowIDss );
+ if ( null != relayIDs && 0 < relayIDs.length ) {
+ long[] rowIDs = rowIDss[0];
+ byte[][][] msgs = NetUtils.queryRelay( this, relayIDs );
if ( null != msgs ) {
- int nameCount = ids.length;
+ RelayMsgSink sink = new RelayMsgSink();
+ int nameCount = relayIDs.length;
ArrayList idsWMsgs =
new ArrayList( nameCount );
for ( int ii = 0; ii < nameCount; ++ii ) {
+ byte[][] forOne = msgs[ii];
// if game has messages, open it and feed 'em
// to it.
- if ( GameUtils.feedMessages( this, ids[ii],
- msgs[ii], sink ) ) {
- idsWMsgs.add( ids[ii] );
+ if ( null == forOne ) {
+ // Nothing for this relayID
+ } else if ( BoardActivity.feedMessages( rowIDs[ii], forOne )
+ || GameUtils.feedMessages( this, rowIDs[ii],
+ forOne, null,
+ sink ) ) {
+ idsWMsgs.add( relayIDs[ii] );
+ } else {
+ DbgUtils.logf( "dropping message for %s (rowid %d)",
+ relayIDs[ii], rowIDs[ii] );
}
}
if ( 0 < idsWMsgs.size() ) {
- String[] relayIDs = new String[idsWMsgs.size()];
- idsWMsgs.toArray( relayIDs );
- setupNotification( relayIDs );
+ String[] tmp = new String[idsWMsgs.size()];
+ idsWMsgs.toArray( tmp );
+ setupNotification( tmp );
}
sink.send( this );
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java
index 24edc0066..3d157d54f 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java
@@ -28,13 +28,13 @@ import java.util.UUID;
import org.eehouse.android.xw4.jni.XwJNI;
public class XWApp extends Application {
- public static final boolean DEBUG_LOCKS = false;
public static final boolean BTSUPPORTED = false;
public static final boolean SMSSUPPORTED = true;
public static final boolean GCMSUPPORTED = true;
public static final boolean ATTACH_SUPPORTED = true;
public static final boolean REMATCH_SUPPORTED = false;
- public static final boolean DEBUG = true; // DON'T SHIP THIS WAY
+ public static final boolean DEBUG = true; // DON'T SHIP THIS WAY
+ public static final boolean DEBUG_LOCKS = false && DEBUG;
public static final String SMS_PUBLIC_HEADER = "-XW4";
From f989dad63c47e3d3efc6d56a3fe5385fadd32e55 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Thu, 13 Dec 2012 07:11:51 -0800
Subject: [PATCH 129/146] tweak changed descriptions
---
xwords4/android/XWords4/res/raw/changes | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/xwords4/android/XWords4/res/raw/changes b/xwords4/android/XWords4/res/raw/changes
index d87b350f7..b9613677d 100644
--- a/xwords4/android/XWords4/res/raw/changes
+++ b/xwords4/android/XWords4/res/raw/changes
@@ -9,13 +9,14 @@
New with this release
- - Include attachment in email invites for devices that don't dispatch
- URLs correctly (e.g. some by HTC)
+ - Include new game information as an attachment in email invites
+ for use on devices that don't dispatch URLs correctly in received
+ email (e.g. some by HTC)
+ - Show final scores alert whenever a finished game is opened -- to
+ make it more clear that it's finished
- Fix flickering in main screen (games list)
- Add option, off by default, to keep rack tiles square even when
the screen is large enough that they can be taller
- - Show final scores alert whenever a finished game is opened -- to
- make it more clear that it's finished
Next up
From 85953c64dd5d789272474939b14e8adbb75492d7 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Thu, 13 Dec 2012 18:47:55 -0800
Subject: [PATCH 130/146] move GameLock into its own file
---
.../eehouse/android/xw4/BoardActivity.java | 4 +-
.../src/org/eehouse/android/xw4/DBUtils.java | 25 ++-
.../org/eehouse/android/xw4/GameConfig.java | 4 +-
.../src/org/eehouse/android/xw4/GameLock.java | 165 ++++++++++++++++++
.../org/eehouse/android/xw4/GameUtils.java | 142 ---------------
.../org/eehouse/android/xw4/GamesList.java | 3 +-
.../android/xw4/RelayGameActivity.java | 4 +-
.../eehouse/android/xw4/jni/JNIThread.java | 5 +-
8 files changed, 187 insertions(+), 165 deletions(-)
create mode 100644 xwords4/android/XWords4/src/org/eehouse/android/xw4/GameLock.java
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
index ff5f5a104..c0bb10d0b 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
@@ -114,7 +114,7 @@ public class BoardActivity extends XWActivity
private BoardView m_view;
private int m_jniGamePtr;
- private GameUtils.GameLock m_gameLock;
+ private GameLock m_gameLock;
private CurGameInfo m_gi;
private CommsTransport m_xport;
private Handler m_handler = null;
@@ -1673,7 +1673,7 @@ public class BoardActivity extends XWActivity
showDictGoneFinish();
} else {
Assert.assertNull( m_gameLock );
- m_gameLock = new GameUtils.GameLock( m_rowid, true ).lock();
+ m_gameLock = new GameLock( m_rowid, true ).lock();
byte[] stream = GameUtils.savedGame( this, m_gameLock );
m_gi = new CurGameInfo( this );
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
index cc6529755..698c9b905 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
@@ -101,8 +101,7 @@ public class DBUtils {
long maxMillis )
{
GameSummary result = null;
- GameUtils.GameLock lock =
- new GameUtils.GameLock( rowid, false ).lock( maxMillis );
+ GameLock lock = new GameLock( rowid, false ).lock( maxMillis );
if ( null != lock ) {
result = getSummary( context, lock );
lock.unlock();
@@ -116,7 +115,7 @@ public class DBUtils {
}
public static GameSummary getSummary( Context context,
- GameUtils.GameLock lock )
+ GameLock lock )
{
initDB( context );
GameSummary summary = null;
@@ -248,13 +247,13 @@ public class DBUtils {
return summary;
} // getSummary
- public static void saveSummary( Context context, GameUtils.GameLock lock,
+ public static void saveSummary( Context context, GameLock lock,
GameSummary summary )
{
saveSummary( context, lock, summary, null );
}
- public static void saveSummary( Context context, GameUtils.GameLock lock,
+ public static void saveSummary( Context context, GameLock lock,
GameSummary summary, String inviteID )
{
Assert.assertTrue( lock.canWrite() );
@@ -679,10 +678,10 @@ public class DBUtils {
}
}
- public static GameUtils.GameLock saveNewGame( Context context,
- byte[] bytes )
+ public static GameLock saveNewGame( Context context,
+ byte[] bytes )
{
- GameUtils.GameLock lock = null;
+ GameLock lock = null;
initDB( context );
synchronized( s_dbHelper ) {
@@ -702,14 +701,14 @@ public class DBUtils {
setCached( rowid, null ); // force reread
clearRowIDsCache();
- lock = new GameUtils.GameLock( rowid, true ).lock();
+ lock = new GameLock( rowid, true ).lock();
notifyListeners( rowid, true );
}
return lock;
}
- public static long saveGame( Context context, GameUtils.GameLock lock,
+ public static long saveGame( Context context, GameLock lock,
byte[] bytes, boolean setCreate )
{
Assert.assertTrue( lock.canWrite() );
@@ -733,7 +732,7 @@ public class DBUtils {
return rowid;
}
- public static byte[] loadGame( Context context, GameUtils.GameLock lock )
+ public static byte[] loadGame( Context context, GameLock lock )
{
long rowid = lock.getRowid();
Assert.assertTrue( -1 != rowid );
@@ -761,12 +760,12 @@ public class DBUtils {
public static void deleteGame( Context context, long rowid )
{
- GameUtils.GameLock lock = new GameUtils.GameLock( rowid, true ).lock();
+ GameLock lock = new GameLock( rowid, true ).lock();
deleteGame( context, lock );
lock.unlock();
}
- public static void deleteGame( Context context, GameUtils.GameLock lock )
+ public static void deleteGame( Context context, GameLock lock )
{
Assert.assertTrue( lock.canWrite() );
initDB( context );
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameConfig.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameConfig.java
index 5fcf33251..c35139e61 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameConfig.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameConfig.java
@@ -92,7 +92,7 @@ public class GameConfig extends XWActivity
private boolean m_forResult;
private CurGameInfo m_gi;
private CurGameInfo m_giOrig;
- private GameUtils.GameLock m_gameLock;
+ private GameLock m_gameLock;
private int m_whichPlayer;
// private Spinner m_roleSpinner;
// private Spinner m_connectSpinner;
@@ -473,7 +473,7 @@ public class GameConfig extends XWActivity
// Lock in case we're going to config. We *could* re-get the
// lock once the user decides to make changes. PENDING.
- m_gameLock = new GameUtils.GameLock( m_rowid, true ).lock();
+ m_gameLock = new GameLock( m_rowid, true ).lock();
int gamePtr = GameUtils.loadMakeGame( this, m_giOrig, m_gameLock );
if ( 0 == gamePtr ) {
showDictGoneFinish();
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameLock.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameLock.java
new file mode 100644
index 000000000..12c080c23
--- /dev/null
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameLock.java
@@ -0,0 +1,165 @@
+/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
+/*
+ * Copyright 2009-2010 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 java.util.HashMap;
+
+import junit.framework.Assert;
+
+// Implements read-locks and write-locks per game. A read lock is
+// obtainable when other read locks are granted but not when a
+// write lock is. Write-locks are exclusive.
+public class GameLock {
+ private long m_rowid;
+ private boolean m_isForWrite;
+ private int m_lockCount;
+ StackTraceElement[] m_lockTrace;
+
+ private static HashMap
+ s_locks = new HashMap();
+
+ public GameLock( long rowid, boolean isForWrite )
+ {
+ m_rowid = rowid;
+ m_isForWrite = isForWrite;
+ m_lockCount = 0;
+ if ( XWApp.DEBUG_LOCKS ) {
+ DbgUtils.logf( "GameLock.GameLock(rowid:%d,isForWrite:%b)=>"
+ + "this: %H", rowid, isForWrite, this );
+ DbgUtils.printStack();
+ }
+ }
+
+ // This could be written to allow multiple read locks. Let's
+ // see if not doing that causes problems.
+ public boolean tryLock()
+ {
+ boolean gotIt = false;
+ synchronized( s_locks ) {
+ GameLock owner = s_locks.get( m_rowid );
+ if ( null == owner ) { // unowned
+ Assert.assertTrue( 0 == m_lockCount );
+ s_locks.put( m_rowid, this );
+ ++m_lockCount;
+ gotIt = true;
+
+ if ( XWApp.DEBUG_LOCKS ) {
+ StackTraceElement[] trace = Thread.currentThread().
+ getStackTrace();
+ m_lockTrace = new StackTraceElement[trace.length];
+ System.arraycopy( trace, 0, m_lockTrace, 0, trace.length );
+ }
+ } else if ( this == owner && ! m_isForWrite ) {
+ Assert.assertTrue( 0 == m_lockCount );
+ ++m_lockCount;
+ gotIt = true;
+ }
+ }
+ return gotIt;
+ }
+
+ // Wait forever (but may assert if too long)
+ public GameLock lock()
+ {
+ return this.lock( 0 );
+ }
+
+ // Version that's allowed to return null -- if maxMillis > 0
+ public GameLock lock( long maxMillis )
+ {
+ GameLock result = null;
+ final long assertTime = 2000;
+ Assert.assertTrue( maxMillis < assertTime );
+ long sleptTime = 0;
+
+ if ( XWApp.DEBUG_LOCKS ) {
+ DbgUtils.logf( "lock %H (rowid:%d, maxMillis=%d)", this, m_rowid, maxMillis );
+ }
+
+ for ( ; ; ) {
+ if ( tryLock() ) {
+ result = this;
+ break;
+ }
+ if ( XWApp.DEBUG_LOCKS ) {
+ DbgUtils.logf( "GameLock.lock() %H failed; sleeping", this );
+ DbgUtils.printStack();
+ }
+ try {
+ Thread.sleep( 25 ); // milliseconds
+ sleptTime += 25;
+ } catch( InterruptedException ie ) {
+ DbgUtils.loge( ie );
+ break;
+ }
+
+ if ( XWApp.DEBUG_LOCKS ) {
+ DbgUtils.logf( "GameLock.lock() %H awake; "
+ + "sleptTime now %d millis", this, sleptTime );
+ }
+
+ if ( 0 < maxMillis && sleptTime >= maxMillis ) {
+ break;
+ } else if ( sleptTime >= assertTime ) {
+ if ( XWApp.DEBUG_LOCKS ) {
+ DbgUtils.logf( "lock %H overlocked. lock holding stack:",
+ this );
+ DbgUtils.printStack( m_lockTrace );
+ DbgUtils.logf( "lock %H seeking stack:", this );
+ DbgUtils.printStack();
+ }
+ Assert.fail();
+ }
+ }
+ // DbgUtils.logf( "GameLock.lock(%s) done", m_path );
+ return result;
+ }
+
+ public void unlock()
+ {
+ // DbgUtils.logf( "GameLock.unlock(%s)", m_path );
+ synchronized( s_locks ) {
+ Assert.assertTrue( this == s_locks.get(m_rowid) );
+ if ( 1 == m_lockCount ) {
+ s_locks.remove( m_rowid );
+ } else {
+ Assert.assertTrue( !m_isForWrite );
+ }
+ --m_lockCount;
+
+ if ( XWApp.DEBUG_LOCKS ) {
+ DbgUtils.logf( "GameLock.unlock: this: %H (rowid:%d) unlocked",
+ this, m_rowid );
+ }
+ }
+ }
+
+ public long getRowid()
+ {
+ return m_rowid;
+ }
+
+ // used only for asserts
+ public boolean canWrite()
+ {
+ return m_isForWrite && 1 == m_lockCount;
+ }
+}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
index e9cc53ce7..e03101184 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
@@ -46,148 +46,6 @@ public class GameUtils {
public static final String INTENT_KEY_ROWID = "rowid";
public static final String INTENT_FORRESULT_ROWID = "forresult";
- // Implements read-locks and write-locks per game. A read lock is
- // obtainable when other read locks are granted but not when a
- // write lock is. Write-locks are exclusive.
- public static class GameLock {
- private long m_rowid;
- private boolean m_isForWrite;
- private int m_lockCount;
- StackTraceElement[] m_lockTrace;
-
- private static HashMap
- s_locks = new HashMap();
-
- public GameLock( long rowid, boolean isForWrite )
- {
- m_rowid = rowid;
- m_isForWrite = isForWrite;
- m_lockCount = 0;
- if ( XWApp.DEBUG_LOCKS ) {
- DbgUtils.logf( "GameLock.GameLock(rowid:%d,isForWrite:%b)=>"
- + "this: %H", rowid, isForWrite, this );
- DbgUtils.printStack();
- }
- }
-
- // This could be written to allow multiple read locks. Let's
- // see if not doing that causes problems.
- public boolean tryLock()
- {
- boolean gotIt = false;
- synchronized( s_locks ) {
- GameLock owner = s_locks.get( m_rowid );
- if ( null == owner ) { // unowned
- Assert.assertTrue( 0 == m_lockCount );
- s_locks.put( m_rowid, this );
- ++m_lockCount;
- gotIt = true;
-
- if ( XWApp.DEBUG_LOCKS ) {
- StackTraceElement[] trace = Thread.currentThread().
- getStackTrace();
- m_lockTrace = new StackTraceElement[trace.length];
- System.arraycopy( trace, 0, m_lockTrace, 0, trace.length );
- }
- } else if ( this == owner && ! m_isForWrite ) {
- Assert.assertTrue( 0 == m_lockCount );
- ++m_lockCount;
- gotIt = true;
- }
- }
- return gotIt;
- }
-
- // Wait forever (but may assert if too long)
- public GameLock lock()
- {
- return this.lock( 0 );
- }
-
- // Version that's allowed to return null -- if maxMillis > 0
- public GameLock lock( long maxMillis )
- {
- GameLock result = null;
- final long assertTime = 2000;
- Assert.assertTrue( maxMillis < assertTime );
- long sleptTime = 0;
-
- if ( XWApp.DEBUG_LOCKS ) {
- DbgUtils.logf( "lock %H (rowid:%d, maxMillis=%d)",
- this, m_rowid, maxMillis );
- }
-
- for ( ; ; ) {
- if ( tryLock() ) {
- result = this;
- break;
- }
- if ( XWApp.DEBUG_LOCKS ) {
- DbgUtils.logf( "GameLock.lock() %H failed (rowid:%d); sleeping",
- this, m_rowid );
- // DbgUtils.printStack();
- }
- try {
- Thread.sleep( 25 ); // milliseconds
- sleptTime += 25;
- } catch( InterruptedException ie ) {
- DbgUtils.loge( ie );
- break;
- }
-
- if ( XWApp.DEBUG_LOCKS ) {
- DbgUtils.logf( "GameLock.lock() %H awake; "
- + "sleptTime now %d millis", this, sleptTime );
- }
-
- if ( 0 < maxMillis && sleptTime >= maxMillis ) {
- break;
- } else if ( sleptTime >= assertTime ) {
- if ( XWApp.DEBUG_LOCKS ) {
- DbgUtils.logf( "lock %H overlocked waiting for rowid:%d. "
- + "lock holding stack:", m_rowid, this );
- DbgUtils.printStack( m_lockTrace );
- DbgUtils.logf( "lock %H seeking stack:", this );
- DbgUtils.printStack();
- }
- Assert.fail();
- }
- }
- // DbgUtils.logf( "GameLock.lock(%s) done", m_path );
- return result;
- }
-
- public void unlock()
- {
- // DbgUtils.logf( "GameLock.unlock(%s)", m_path );
- synchronized( s_locks ) {
- Assert.assertTrue( this == s_locks.get(m_rowid) );
- if ( 1 == m_lockCount ) {
- s_locks.remove( m_rowid );
- } else {
- Assert.assertTrue( !m_isForWrite );
- }
- --m_lockCount;
-
- if ( XWApp.DEBUG_LOCKS ) {
- DbgUtils.logf( "GameLock.unlock: this: %H (rowid:%d) "
- + "unlocked", this, m_rowid );
- }
- }
- }
-
- public long getRowid()
- {
- return m_rowid;
- }
-
- // used only for asserts
- public boolean canWrite()
- {
- return m_isForWrite && 1 == m_lockCount;
- }
- }
-
private static Object s_syncObj = new Object();
public static byte[] savedGame( Context context, long rowid )
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
index 833c4eac4..2d3ca4f37 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
@@ -651,8 +651,7 @@ public class GamesList extends XWListActivity
showOKOnlyDialog( R.string.no_copy_network );
} else {
byte[] stream = GameUtils.savedGame( this, m_rowid );
- GameUtils.GameLock lock =
- GameUtils.saveNewGame( this, stream );
+ GameLock lock = GameUtils.saveNewGame( this, stream );
DBUtils.saveSummary( this, lock, summary );
lock.unlock();
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayGameActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayGameActivity.java
index e5571a6a1..d3f4a6795 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayGameActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayGameActivity.java
@@ -41,7 +41,7 @@ public class RelayGameActivity extends XWActivity
private long m_rowid;
private CurGameInfo m_gi;
- private GameUtils.GameLock m_gameLock;
+ private GameLock m_gameLock;
private CommsAddrRec m_car;
private Button m_playButton;
private Button m_configButton;
@@ -68,7 +68,7 @@ public class RelayGameActivity extends XWActivity
super.onStart();
m_gi = new CurGameInfo( this );
- m_gameLock = new GameUtils.GameLock( m_rowid, true ).lock();
+ m_gameLock = new GameLock( m_rowid, true ).lock();
int gamePtr = GameUtils.loadMakeGame( this, m_gi, m_gameLock );
m_car = new CommsAddrRec();
if ( XwJNI.game_hasComms( gamePtr ) ) {
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java
index 71577dc6a..e39adc389 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java
@@ -34,6 +34,7 @@ import org.eehouse.android.xw4.R;
import org.eehouse.android.xw4.DbgUtils;
import org.eehouse.android.xw4.ConnStatusHandler;
import org.eehouse.android.xw4.BoardDims;
+import org.eehouse.android.xw4.GameLock;
import org.eehouse.android.xw4.GameUtils;
import org.eehouse.android.xw4.DBUtils;
import org.eehouse.android.xw4.Toolbar;
@@ -121,7 +122,7 @@ public class JNIThread extends Thread {
private boolean m_stopped = false;
private boolean m_saveOnStop = false;
private int m_jniGamePtr;
- private GameUtils.GameLock m_lock;
+ private GameLock m_lock;
private Context m_context;
private CurGameInfo m_gi;
private Handler m_handler;
@@ -143,7 +144,7 @@ public class JNIThread extends Thread {
}
public JNIThread( int gamePtr, CurGameInfo gi, SyncedDraw drawer,
- GameUtils.GameLock lock, Context context, Handler handler )
+ GameLock lock, Context context, Handler handler )
{
m_jniGamePtr = gamePtr;
m_gi = gi;
From 7a1de73fb79b71ab5c876934f8ad41cd155ec6a9 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Thu, 13 Dec 2012 20:18:36 -0800
Subject: [PATCH 131/146] remove unused file
---
xwords4/android/XWords4/res/layout/game_list_tmp.xml | 11 -----------
1 file changed, 11 deletions(-)
delete mode 100644 xwords4/android/XWords4/res/layout/game_list_tmp.xml
diff --git a/xwords4/android/XWords4/res/layout/game_list_tmp.xml b/xwords4/android/XWords4/res/layout/game_list_tmp.xml
deleted file mode 100644
index 00ec641a9..000000000
--- a/xwords4/android/XWords4/res/layout/game_list_tmp.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
From 322a65ee412817f0a396fd4032179b137cae47e3 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Thu, 13 Dec 2012 20:22:11 -0800
Subject: [PATCH 132/146] in several places where lock() was being called
without a timeout, add one, and fail gracefully when a timeout occurs.
---
.../src/org/eehouse/android/xw4/DBUtils.java | 13 +--
.../org/eehouse/android/xw4/GameUtils.java | 81 +++++++++++--------
.../org/eehouse/android/xw4/GamesList.java | 20 +++--
.../android/xw4/RelayGameActivity.java | 34 ++++----
4 files changed, 89 insertions(+), 59 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
index 698c9b905..235dc108f 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
@@ -678,8 +678,7 @@ public class DBUtils {
}
}
- public static GameLock saveNewGame( Context context,
- byte[] bytes )
+ public static GameLock saveNewGame( Context context, byte[] bytes )
{
GameLock lock = null;
@@ -760,9 +759,13 @@ public class DBUtils {
public static void deleteGame( Context context, long rowid )
{
- GameLock lock = new GameLock( rowid, true ).lock();
- deleteGame( context, lock );
- lock.unlock();
+ GameLock lock = new GameLock( rowid, true ).lock( 300 );
+ if ( null != lock ) {
+ deleteGame( context, lock );
+ lock.unlock();
+ } else {
+ DbgUtils.logf( "deleteGame: unable to lock rowid %d", rowid );
+ }
}
public static void deleteGame( Context context, GameLock lock )
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
index e03101184..eb9f18303 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
@@ -114,12 +114,16 @@ public class GameUtils {
public static void resetGame( Context context, long rowidIn )
{
- GameLock lock = new GameLock( rowidIn, true ).lock();
- tellDied( context, lock, true );
- resetGame( context, lock, lock, false );
- lock.unlock();
+ GameLock lock = new GameLock( rowidIn, true ).lock( 500 );
+ if ( null != lock ) {
+ tellDied( context, lock, true );
+ resetGame( context, lock, lock, false );
+ lock.unlock();
- Utils.cancelNotification( context, (int)rowidIn );
+ Utils.cancelNotification( context, (int)rowidIn );
+ } else {
+ DbgUtils.logf( "resetGame: unable to open rowid %d", rowidIn );
+ }
}
private static GameSummary summarizeAndClose( Context context,
@@ -172,12 +176,17 @@ public class GameUtils {
public static long dupeGame( Context context, long rowidIn )
{
- boolean juggle = CommonPrefs.getAutoJuggle( context );
- GameLock lockSrc = new GameLock( rowidIn, false ).lock();
- GameLock lockDest = resetGame( context, lockSrc, null, juggle );
- long rowid = lockDest.getRowid();
- lockDest.unlock();
- lockSrc.unlock();
+ long rowid = DBUtils.ROWID_NOTFOUND;
+ GameLock lockSrc = new GameLock( rowidIn, false ).lock( 300 );
+ if ( null != lockSrc ) {
+ boolean juggle = CommonPrefs.getAutoJuggle( context );
+ GameLock lockDest = resetGame( context, lockSrc, null, juggle );
+ rowid = lockDest.getRowid();
+ lockDest.unlock();
+ lockSrc.unlock();
+ } else {
+ DbgUtils.logf( "dupeGame: unable to open rowid %d", rowidIn );
+ }
return rowid;
}
@@ -634,34 +643,42 @@ public class GameUtils {
// This *must* involve a reset if the language is changing!!!
// Which isn't possible right now, so make sure the old and new
// dict have the same langauge code.
- public static void replaceDicts( Context context, long rowid,
- String oldDict, String newDict )
+ public static boolean replaceDicts( Context context, long rowid,
+ String oldDict, String newDict )
{
- GameLock lock = new GameLock( rowid, true ).lock();
- byte[] stream = savedGame( context, lock );
- CurGameInfo gi = new CurGameInfo( context );
- XwJNI.gi_from_stream( gi, stream );
+ GameLock lock = new GameLock( rowid, true ).lock(300);
+ boolean success = null != lock;
+ if ( success ) {
+ byte[] stream = savedGame( context, lock );
+ CurGameInfo gi = new CurGameInfo( context );
+ XwJNI.gi_from_stream( gi, stream );
- // first time required so dictNames() will work
- gi.replaceDicts( newDict );
+ // first time required so dictNames() will work
+ gi.replaceDicts( newDict );
- String[] dictNames = gi.dictNames();
- DictUtils.DictPairs pairs = DictUtils.openDicts( context, dictNames );
+ String[] dictNames = gi.dictNames();
+ DictUtils.DictPairs pairs = DictUtils.openDicts( context,
+ dictNames );
- int gamePtr = XwJNI.initJNI();
- XwJNI.game_makeFromStream( gamePtr, stream, gi, dictNames,
- pairs.m_bytes, pairs.m_paths,
- gi.langName(), JNIUtilsImpl.get(context),
- CommonPrefs.get( context ) );
- // second time required as game_makeFromStream can overwrite
- gi.replaceDicts( newDict );
+ int gamePtr = XwJNI.initJNI();
+ XwJNI.game_makeFromStream( gamePtr, stream, gi, dictNames,
+ pairs.m_bytes, pairs.m_paths,
+ gi.langName(),
+ JNIUtilsImpl.get(context),
+ CommonPrefs.get( context ) );
+ // second time required as game_makeFromStream can overwrite
+ gi.replaceDicts( newDict );
- saveGame( context, gamePtr, gi, lock, false );
+ saveGame( context, gamePtr, gi, lock, false );
- summarizeAndClose( context, lock, gamePtr, gi );
+ summarizeAndClose( context, lock, gamePtr, gi );
- lock.unlock();
- }
+ lock.unlock();
+ } else {
+ DbgUtils.logf( "replaceDicts: unable to open rowid %d", rowid );
+ }
+ return success;
+ } // replaceDicts
public static void applyChanges( Context context, CurGameInfo gi,
CommsAddrRec car, GameLock lock,
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
index 2d3ca4f37..83be99efb 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
@@ -165,11 +165,12 @@ public class GamesList extends XWListActivity
getCheckedItemPosition();
String dict = m_sameLangDicts[pos];
dict = DictLangCache.stripCount( dict );
- GameUtils.replaceDicts( GamesList.this,
- m_missingDictRowId,
- m_missingDictName,
- dict );
- launchGameIf();
+ if ( GameUtils.replaceDicts( GamesList.this,
+ m_missingDictRowId,
+ m_missingDictName,
+ dict ) ) {
+ launchGameIf();
+ }
}
};
dialog = new AlertDialog.Builder( this )
@@ -721,9 +722,12 @@ public class GamesList extends XWListActivity
} else if ( null != m_missingDictName ) {
showDialog( WARN_NODICT_SUBST );
} else {
- String dict = DictLangCache.getHaveLang( this, m_missingDictLang)[0];
- GameUtils.replaceDicts( this, m_missingDictRowId, null, dict );
- launchGameIf();
+ String dict =
+ DictLangCache.getHaveLang( this, m_missingDictLang)[0];
+ if ( GameUtils.replaceDicts( this, m_missingDictRowId,
+ null, dict ) ) {
+ launchGameIf();
+ }
}
}
return hasDicts;
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayGameActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayGameActivity.java
index d3f4a6795..16ead9288 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayGameActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayGameActivity.java
@@ -68,22 +68,28 @@ public class RelayGameActivity extends XWActivity
super.onStart();
m_gi = new CurGameInfo( this );
- m_gameLock = new GameLock( m_rowid, true ).lock();
- int gamePtr = GameUtils.loadMakeGame( this, m_gi, m_gameLock );
- m_car = new CommsAddrRec();
- if ( XwJNI.game_hasComms( gamePtr ) ) {
- XwJNI.comms_getAddr( gamePtr, m_car );
+ m_gameLock = new GameLock( m_rowid, true ).lock( 300 );
+ if ( null == m_gameLock ) {
+ DbgUtils.logf( "RelayGameActivity.onStart(): unable to lock rowid %d",
+ m_rowid );
+ finish();
} else {
- Assert.fail();
- // String relayName = CommonPrefs.getDefaultRelayHost( this );
- // int relayPort = CommonPrefs.getDefaultRelayPort( this );
- // XwJNI.comms_getInitialAddr( m_carOrig, relayName, relayPort );
- }
- XwJNI.game_dispose( gamePtr );
+ int gamePtr = GameUtils.loadMakeGame( this, m_gi, m_gameLock );
+ m_car = new CommsAddrRec();
+ if ( XwJNI.game_hasComms( gamePtr ) ) {
+ XwJNI.comms_getAddr( gamePtr, m_car );
+ } else {
+ Assert.fail();
+ // String relayName = CommonPrefs.getDefaultRelayHost( this );
+ // int relayPort = CommonPrefs.getDefaultRelayPort( this );
+ // XwJNI.comms_getInitialAddr( m_carOrig, relayName, relayPort );
+ }
+ XwJNI.game_dispose( gamePtr );
- String lang = DictLangCache.getLangName( this, m_gi.dictLang );
- TextView text = (TextView)findViewById( R.id.explain );
- text.setText( getString( R.string.relay_game_explainf, lang ) );
+ String lang = DictLangCache.getLangName( this, m_gi.dictLang );
+ TextView text = (TextView)findViewById( R.id.explain );
+ text.setText( getString( R.string.relay_game_explainf, lang ) );
+ }
}
@Override
From 028899a9c453bb29da9041362466b0d48f146806 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Fri, 14 Dec 2012 07:24:26 -0800
Subject: [PATCH 133/146] no need to set action on local intent
---
.../android/XWords4/src/org/eehouse/android/xw4/GameUtils.java | 1 -
1 file changed, 1 deletion(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
index eb9f18303..1e203a90c 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
@@ -538,7 +538,6 @@ public class GameUtils {
boolean invited )
{
Intent intent = new Intent( activity, BoardActivity.class );
- intent.setAction( Intent.ACTION_EDIT );
intent.putExtra( INTENT_KEY_ROWID, rowid );
if ( invited ) {
intent.putExtra( INVITED, true );
From 8125c451cd994d90e0376c31cc53af5bff3593d5 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Fri, 14 Dec 2012 07:26:13 -0800
Subject: [PATCH 134/146] in GamesList, save rowid of launched game and inval
it afterwards so scores etc. get updated.
---
.../org/eehouse/android/xw4/GamesList.java | 27 ++++++++++++++-----
1 file changed, 21 insertions(+), 6 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
index 83be99efb..2fa53e3b1 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
@@ -91,7 +91,7 @@ public class GamesList extends XWListActivity
private int m_missingDictLang;
private long m_rowid;
private NetLaunchInfo m_netLaunchInfo;
- // private String m_smsPhone;
+ private long m_invalRowID = DBUtils.ROWID_NOTFOUND;
@Override
protected Dialog onCreateDialog( int id )
@@ -379,6 +379,10 @@ public class GamesList extends XWListActivity
if ( hasFocus ) {
updateField();
}
+ if ( hasFocus && DBUtils.ROWID_NOTFOUND != m_invalRowID ) {
+ m_adapter.inval( m_invalRowID );
+ m_invalRowID = DBUtils.ROWID_NOTFOUND;
+ }
}
// DBUtils.DBChangeListener interface
@@ -415,7 +419,7 @@ public class GamesList extends XWListActivity
GameUtils.doConfig( this, rowid, clazz );
} else {
if ( checkWarnNoDict( rowid ) ) {
- GameUtils.launchGame( this, rowid );
+ launchGame( rowid );
}
}
}
@@ -758,7 +762,7 @@ public class GamesList extends XWListActivity
if ( null != rowids ) {
for ( long rowid : rowids ) {
if ( GameUtils.gameDictsHere( this, rowid ) ) {
- GameUtils.launchGame( this, rowid );
+ launchGame( rowid );
break outer;
}
}
@@ -816,7 +820,7 @@ public class GamesList extends XWListActivity
{
long[] rowids = DBUtils.getRowIDsFor( this, gameID );
if ( null != rowids && 0 < rowids.length ) {
- GameUtils.launchGame( this, rowids[0] );
+ launchGame( rowids[0] );
}
}
@@ -834,7 +838,7 @@ public class GamesList extends XWListActivity
if ( -1 != rowid ) {
// this will juggle if the preference is set
long newid = GameUtils.dupeGame( this, rowid );
- GameUtils.launchGame( this, newid );
+ launchGame( newid );
}
}
@@ -877,10 +881,21 @@ public class GamesList extends XWListActivity
return madeGame;
}
+ private void launchGame( long rowid, boolean invited )
+ {
+ m_invalRowID = rowid;
+ GameUtils.launchGame( this, rowid, invited );
+ }
+
+ private void launchGame( long rowid )
+ {
+ launchGame( rowid, false );
+ }
+
private void makeNewNetGame( NetLaunchInfo info )
{
long rowid = GameUtils.makeNewNetGame( this, info );
- GameUtils.launchGame( this, rowid, true );
+ launchGame( rowid, true );
}
public static void onGameDictDownload( Context context, Intent intent )
From 646ec65d6645e95f35e1ae91f8d3c33193563d7b Mon Sep 17 00:00:00 2001
From: Eric House
Date: Fri, 14 Dec 2012 18:23:33 -0800
Subject: [PATCH 135/146] wrap elapsed time logging in its own debug flag and
turn off.
---
.../XWords4/src/org/eehouse/android/xw4/ExpiringDelegate.java | 4 ++--
.../android/XWords4/src/org/eehouse/android/xw4/XWApp.java | 1 +
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/ExpiringDelegate.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/ExpiringDelegate.java
index 13083266d..e1cedab05 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/ExpiringDelegate.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/ExpiringDelegate.java
@@ -194,7 +194,7 @@ public class ExpiringDelegate {
if ( null == m_runnable ) {
m_runnable = new Runnable() {
public void run() {
- if ( XWApp.DEBUG ) {
+ if ( XWApp.DEBUG_EXP_TIMERS ) {
DbgUtils.logf( "ExpiringDelegate: timer fired"
+ " for %H", this );
}
@@ -204,7 +204,7 @@ public class ExpiringDelegate {
m_back = null;
setBackground();
}
- if ( XWApp.DEBUG ) {
+ if ( XWApp.DEBUG_EXP_TIMERS ) {
DbgUtils.logf( "ExpiringDelegate: invalidating"
+ " view %H", m_view );
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java
index 3d157d54f..51d7db703 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java
@@ -35,6 +35,7 @@ public class XWApp extends Application {
public static final boolean REMATCH_SUPPORTED = false;
public static final boolean DEBUG = true; // DON'T SHIP THIS WAY
public static final boolean DEBUG_LOCKS = false && DEBUG;
+ public static final boolean DEBUG_EXP_TIMERS = false && DEBUG;
public static final String SMS_PUBLIC_HEADER = "-XW4";
From 3c4f266b8ffece2f53110e3ffc2311ec1fe06251 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Fri, 14 Dec 2012 18:46:54 -0800
Subject: [PATCH 136/146] work around problems locating GameListItems when it's
time to invalidate them by adding static list of those needing invalidating
and checking it in a new onDraw override.
---
.../eehouse/android/xw4/GameListAdapter.java | 3 +-
.../org/eehouse/android/xw4/GameListItem.java | 100 ++++++++++++++----
2 files changed, 79 insertions(+), 24 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java
index 26405c0a2..47b398964 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java
@@ -90,10 +90,11 @@ public class GameListAdapter extends XWListAdapter {
public void inval( long rowid )
{
GameListItem child = getItemFor( rowid );
- if ( null != child ) {
+ if ( null != child && child.getRowID() == rowid ) {
child.forceReload();
} else {
DbgUtils.logf( "no child for rowid %d", rowid );
+ GameListItem.inval( rowid );
m_list.invalidate();
}
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListItem.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListItem.java
index d5d727b08..9cd376d18 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListItem.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListItem.java
@@ -21,8 +21,10 @@
package org.eehouse.android.xw4;
import android.content.Context;
+import android.graphics.Canvas;
import android.os.AsyncTask;
import android.os.Handler;
+// import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageButton;
@@ -31,6 +33,8 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import java.text.DateFormat;
import java.util.Date;
+import java.util.HashSet;
+// import java.util.Iterator;
import org.eehouse.android.xw4.jni.GameSummary;
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
@@ -38,6 +42,8 @@ import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
public class GameListItem extends LinearLayout
implements View.OnClickListener {
+ private static HashSet s_invalRows = new HashSet();
+
private Context m_context;
private boolean m_loaded;
private long m_rowid;
@@ -50,6 +56,7 @@ public class GameListItem extends LinearLayout
private GameSummary m_summary;
private GameListAdapter.LoadItemCB m_cb;
private int m_fieldID;
+ private int m_loadingCount;
public GameListItem( Context cx, AttributeSet as )
{
@@ -58,6 +65,7 @@ public class GameListItem extends LinearLayout
m_loaded = false;
m_rowid = DBUtils.ROWID_NOTFOUND;
m_lastMoveTime = 0;
+ m_loadingCount = 0;
}
public void init( Handler handler, long rowid, int fieldID,
@@ -73,7 +81,13 @@ public class GameListItem extends LinearLayout
public void forceReload()
{
+ // DbgUtils.logf( "GameListItem.forceReload: rowid=%d", m_rowid );
m_summary = null;
+ setLoaded( false );
+ // Apparently it's impossible to reliably cancel an existing
+ // AsyncTask, so let it complete, but drop the results as soon
+ // as we're back on the UI thread.
+ ++m_loadingCount;
new LoadItemTask().execute();
}
@@ -82,6 +96,19 @@ public class GameListItem extends LinearLayout
setName();
}
+ @Override
+ protected void onDraw( Canvas canvas )
+ {
+ super.onDraw( canvas );
+ if ( DBUtils.ROWID_NOTFOUND != m_rowid ) {
+ synchronized( s_invalRows ) {
+ if ( s_invalRows.contains( m_rowid ) ) {
+ forceReload();
+ }
+ }
+ }
+ }
+
private void update( boolean expanded, long lastMoveTime, boolean haveTurn,
boolean haveTurnLocal )
{
@@ -108,15 +135,15 @@ public class GameListItem extends LinearLayout
showHide();
}
- private void setLoaded()
+ private void setLoaded( boolean loaded )
{
- if ( !m_loaded ) {
- m_loaded = true;
+ if ( loaded != m_loaded ) {
+ m_loaded = loaded;
// This should be enough to invalidate
findViewById( R.id.view_unloaded )
- .setVisibility( m_loaded ? View.GONE : View.VISIBLE );
+ .setVisibility( loaded ? View.GONE : View.VISIBLE );
findViewById( R.id.view_loaded )
- .setVisibility( m_loaded ? View.VISIBLE : View.GONE );
+ .setVisibility( loaded ? View.VISIBLE : View.GONE );
}
}
@@ -168,16 +195,16 @@ public class GameListItem extends LinearLayout
return state;
}
- private void setData()
+ private void setData( final GameSummary summary )
{
- if ( null != m_summary ) {
+ if ( null != summary ) {
TextView view;
String state = setName();
setOnClickListener( new View.OnClickListener() {
@Override
public void onClick( View v ) {
- m_cb.itemClicked( m_rowid, m_summary );
+ m_cb.itemClicked( m_rowid, summary );
}
} );
@@ -187,14 +214,14 @@ public class GameListItem extends LinearLayout
boolean haveATurn = false;
boolean haveALocalTurn = false;
boolean[] isLocal = new boolean[1];
- for ( int ii = 0; ii < m_summary.nPlayers; ++ii ) {
+ for ( int ii = 0; ii < summary.nPlayers; ++ii ) {
ExpiringLinearLayout tmp = (ExpiringLinearLayout)
Utils.inflate( m_context, R.layout.player_list_elem );
view = (TextView)tmp.findViewById( R.id.item_name );
- view.setText( m_summary.summarizePlayer( ii ) );
+ view.setText( summary.summarizePlayer( ii ) );
view = (TextView)tmp.findViewById( R.id.item_score );
- view.setText( String.format( " %d", m_summary.scores[ii] ) );
- boolean thisHasTurn = m_summary.isNextToPlay( ii, isLocal );
+ view.setText( String.format( " %d", summary.scores[ii] ) );
+ boolean thisHasTurn = summary.isNextToPlay( ii, isLocal );
if ( thisHasTurn ) {
haveATurn = true;
if ( isLocal[0] ) {
@@ -202,14 +229,14 @@ public class GameListItem extends LinearLayout
}
}
tmp.setPct( m_handler, thisHasTurn, isLocal[0],
- m_summary.lastMoveTime );
+ summary.lastMoveTime );
list.addView( tmp, ii );
}
view = (TextView)findViewById( R.id.state );
view.setText( state );
view = (TextView)findViewById( R.id.modtime );
- long lastMoveTime = m_summary.lastMoveTime;
+ long lastMoveTime = summary.lastMoveTime;
lastMoveTime *= 1000;
DateFormat df = DateFormat.getDateTimeInstance( DateFormat.SHORT,
@@ -219,7 +246,7 @@ public class GameListItem extends LinearLayout
int iconID;
ImageView marker =
(ImageView)findViewById( R.id.msg_marker );
- CommsConnType conType = m_summary.conType;
+ CommsConnType conType = summary.conType;
if ( CommsConnType.COMMS_CONN_RELAY == conType ) {
iconID = R.drawable.relaygame;
} else if ( CommsConnType.COMMS_CONN_BT == conType ) {
@@ -232,7 +259,7 @@ public class GameListItem extends LinearLayout
marker.setImageResource( iconID );
view = (TextView)findViewById( R.id.role );
- String roleSummary = m_summary.summarizeRole();
+ String roleSummary = summary.summarizeRole();
if ( null != roleSummary ) {
view.setText( roleSummary );
} else {
@@ -241,7 +268,7 @@ public class GameListItem extends LinearLayout
boolean expanded = DBUtils.getExpanded( m_context, m_rowid );
- update( expanded, m_summary.lastMoveTime, haveATurn,
+ update( expanded, summary.lastMoveTime, haveATurn,
haveALocalTurn );
}
}
@@ -256,13 +283,40 @@ public class GameListItem extends LinearLayout
@Override
protected void onPostExecute( GameSummary summary )
{
- m_summary = summary;
- setData();
- // setLoaded( m_view.getRowID() );
- setLoaded();
-
- // DbgUtils.logf( "LoadItemTask for row %d finished", m_rowid );
+ if ( 0 == --m_loadingCount ) {
+ m_summary = summary;
+ setData( summary );
+ setLoaded( null != m_summary );
+ synchronized( s_invalRows ) {
+ s_invalRows.remove( m_rowid );
+ }
+ }
+ // DbgUtils.logf( "LoadItemTask for row %d finished; "
+ // + "inval rows now %s",
+ // m_rowid, invalRowsToString() );
}
} // class LoadItemTask
+ public static void inval( long rowid )
+ {
+ synchronized( s_invalRows ) {
+ s_invalRows.add( rowid );
+ }
+ // DbgUtils.logf( "GameListItem.inval(rowid=%d); inval rows now %s",
+ // rowid, invalRowsToString() );
+ }
+
+ // private static String invalRowsToString()
+ // {
+ // String[] strs;
+ // synchronized( s_invalRows ) {
+ // strs = new String[s_invalRows.size()];
+ // Iterator iter = s_invalRows.iterator();
+ // for ( int ii = 0; iter.hasNext(); ++ii ) {
+ // strs[ii] = String.format("%d", iter.next() );
+ // }
+ // }
+ // return TextUtils.join(",", strs );
+ // }
+
}
From 51a5e80a267f487acdc7691d8ab55aa106711ba7 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Sun, 16 Dec 2012 15:13:36 -0800
Subject: [PATCH 137/146] mention attachment in invite email text
---
xwords4/android/XWords4/res/values/strings.xml | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/xwords4/android/XWords4/res/values/strings.xml b/xwords4/android/XWords4/res/values/strings.xml
index cdd796f20..e9288214b 100644
--- a/xwords4/android/XWords4/res/values/strings.xml
+++ b/xwords4/android/XWords4/res/values/strings.xml
@@ -1229,8 +1229,10 @@
encodings for the greater-than and less-than symbols which
are not legal in xml strings.)-->
\u003ca href=\"%1$s\"\u003ETap
- here\u003c/a\u003E (or the full link below) to accept my invitation and
- join this game.
+ here\u003c/a\u003E (or tap the full link below, or, if you already
+ have Crosswords installed, open the attachment) to accept my
+ invitation and join this game.
+
\u003cbr \\\u003E
\u003cbr \\\u003E
(full link: %1$s)
From e38b99c0c8feedf2aa06030d15c1988aa1497bcf Mon Sep 17 00:00:00 2001
From: Eric House
Date: Sun, 16 Dec 2012 15:14:04 -0800
Subject: [PATCH 138/146] set DEBUG to false for release
---
xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java
index 51d7db703..1f0790181 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java
@@ -33,7 +33,7 @@ public class XWApp extends Application {
public static final boolean GCMSUPPORTED = true;
public static final boolean ATTACH_SUPPORTED = true;
public static final boolean REMATCH_SUPPORTED = false;
- public static final boolean DEBUG = true; // DON'T SHIP THIS WAY
+ public static final boolean DEBUG = false;
public static final boolean DEBUG_LOCKS = false && DEBUG;
public static final boolean DEBUG_EXP_TIMERS = false && DEBUG;
From 60adf36718116aeabe67e65e78accbced74101fc Mon Sep 17 00:00:00 2001
From: Eric House
Date: Sun, 16 Dec 2012 15:14:33 -0800
Subject: [PATCH 139/146] fix typo
---
xwords4/android/scripts/and_index.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/xwords4/android/scripts/and_index.php b/xwords4/android/scripts/and_index.php
index 01dac83c2..7d0a53cc1 100644
--- a/xwords4/android/scripts/and_index.php
+++ b/xwords4/android/scripts/and_index.php
@@ -75,8 +75,8 @@ link in your invite email (or text) again, and this time let
Crosswords handle it.
(If you get tired of having to having to make that choice, Android
-will allow you to make Crosswords the default. What you're saying is
-that Crosswords will be giving control of all URLs that start with
+will allow you to make Crosswords the default. If you do that
+Crosswords will be given control of all URLs that start with
"http://eehouse.org/and/" -- not all URLs of any type.)
Have fun. And as always, let
From 9d7d0aca2bf21652047613e5ccac3bbfd70c1580 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Sun, 16 Dec 2012 20:14:15 -0800
Subject: [PATCH 140/146] cleanup: logging and unused imports
---
.../src/org/eehouse/android/xw4/DBUtils.java | 1 -
.../org/eehouse/android/xw4/GameListAdapter.java | 14 --------------
.../src/org/eehouse/android/xw4/GameUtils.java | 2 --
3 files changed, 17 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
index 235dc108f..84a8bcae5 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
@@ -813,7 +813,6 @@ public class DBUtils {
private static void clearRowIDsCache()
{
- DbgUtils.logf( "DBUtils.clearRowIDsCache()" );
synchronized( DBUtils.class ) {
s_cachedRowIDs = null;
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java
index 47b398964..4a6290d7e 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java
@@ -20,26 +20,15 @@
package org.eehouse.android.xw4;
import android.content.Context;
-import android.database.DataSetObserver;
-import android.os.Build;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
import android.widget.ListAdapter;
import android.widget.ListView;
-import android.widget.TextView;
-import java.io.FileInputStream;
-import java.text.DateFormat;
-import java.util.Date;
-import java.util.Random;
import junit.framework.Assert;
-
import org.eehouse.android.xw4.jni.*;
import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole;
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
@@ -50,7 +39,6 @@ public class GameListAdapter extends XWListAdapter {
private LayoutInflater m_factory;
private int m_fieldID;
private Handler m_handler;
- private DateFormat m_df;
private LoadItemCB m_cb;
public interface LoadItemCB {
@@ -65,8 +53,6 @@ public class GameListAdapter extends XWListAdapter {
m_handler = handler;
m_cb = cb;
m_factory = LayoutInflater.from( context );
- m_df = DateFormat.getDateTimeInstance( DateFormat.SHORT,
- DateFormat.SHORT );
m_fieldID = fieldToID( fieldName );
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
index 1e203a90c..37b765f6a 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
@@ -430,8 +430,6 @@ public class GameUtils {
String mime = context.getString( R.string.invite_mime );
intent.setType( mime );
Uri uri = Uri.fromFile( attach );
- DbgUtils.logf( "using file uri %s, type %s for attachment",
- uri.toString(), mime );
intent.putExtra( Intent.EXTRA_STREAM, uri );
}
From 6988b1424737d9ea4d9aa9efc9d6e56935a03102 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Tue, 18 Dec 2012 05:40:25 -0800
Subject: [PATCH 141/146] no need for redraw in onWindowFocusChanged
---
.../XWords4/src/org/eehouse/android/xw4/GamesList.java | 6 ------
1 file changed, 6 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
index 2fa53e3b1..84bfba2ae 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
@@ -91,7 +91,6 @@ public class GamesList extends XWListActivity
private int m_missingDictLang;
private long m_rowid;
private NetLaunchInfo m_netLaunchInfo;
- private long m_invalRowID = DBUtils.ROWID_NOTFOUND;
@Override
protected Dialog onCreateDialog( int id )
@@ -379,10 +378,6 @@ public class GamesList extends XWListActivity
if ( hasFocus ) {
updateField();
}
- if ( hasFocus && DBUtils.ROWID_NOTFOUND != m_invalRowID ) {
- m_adapter.inval( m_invalRowID );
- m_invalRowID = DBUtils.ROWID_NOTFOUND;
- }
}
// DBUtils.DBChangeListener interface
@@ -883,7 +878,6 @@ public class GamesList extends XWListActivity
private void launchGame( long rowid, boolean invited )
{
- m_invalRowID = rowid;
GameUtils.launchGame( this, rowid, invited );
}
From 8cb9d3d66b61a0f2fdd451572d3610523c969b01 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Tue, 18 Dec 2012 05:56:14 -0800
Subject: [PATCH 142/146] turn debug back on
---
xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java
index 1f0790181..d3d02f534 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java
@@ -33,7 +33,7 @@ public class XWApp extends Application {
public static final boolean GCMSUPPORTED = true;
public static final boolean ATTACH_SUPPORTED = true;
public static final boolean REMATCH_SUPPORTED = false;
- public static final boolean DEBUG = false;
+ public static final boolean DEBUG = true;
public static final boolean DEBUG_LOCKS = false && DEBUG;
public static final boolean DEBUG_EXP_TIMERS = false && DEBUG;
From db829337f5ae4faff9c93e0e0a1bcb2db05111f8 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Thu, 20 Dec 2012 21:51:38 -0800
Subject: [PATCH 143/146] up version strings etc.
---
xwords4/android/XWords4/AndroidManifest.xml | 2 +-
xwords4/android/XWords4/res/raw/changes | 15 ++++-----------
xwords4/android/XWords4/res/values/app_name.xml | 2 +-
3 files changed, 6 insertions(+), 13 deletions(-)
diff --git a/xwords4/android/XWords4/AndroidManifest.xml b/xwords4/android/XWords4/AndroidManifest.xml
index 1b634d862..a1446e4b8 100644
--- a/xwords4/android/XWords4/AndroidManifest.xml
+++ b/xwords4/android/XWords4/AndroidManifest.xml
@@ -22,7 +22,7 @@
to come from a domain that you own or have control over. -->
diff --git a/xwords4/android/XWords4/res/raw/changes b/xwords4/android/XWords4/res/raw/changes
index b9613677d..98a8b8f2b 100644
--- a/xwords4/android/XWords4/res/raw/changes
+++ b/xwords4/android/XWords4/res/raw/changes
@@ -5,24 +5,17 @@
-Crosswords 4.4 beta 57 release
+Crosswords 4.4 beta 58 release
New with this release
- - Include new game information as an attachment in email invites
- for use on devices that don't dispatch URLs correctly in received
- email (e.g. some by HTC)
- - Show final scores alert whenever a finished game is opened -- to
- make it more clear that it's finished
- - Fix flickering in main screen (games list)
- - Add option, off by default, to keep rack tiles square even when
- the screen is large enough that they can be taller
+ - Allow grouping of games in collapsible user-defined categores:
+ "Games with Kati", "Finished games", etc.
Next up
- - Allow grouping of games in collapsible user-defined categores: "Games with
- Kati", "Finished games", etc.
+ - Improve communication with relay
(The full changelog
diff --git a/xwords4/android/XWords4/res/values/app_name.xml b/xwords4/android/XWords4/res/values/app_name.xml
index 095652a34..59b7fb0f8 100644
--- a/xwords4/android/XWords4/res/values/app_name.xml
+++ b/xwords4/android/XWords4/res/values/app_name.xml
@@ -1,5 +1,5 @@
- 4.4 beta 57
+ 4.4 beta 58
From 1743382e1f7f277a8c8a843e397e5c6dec373dc7 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Thu, 20 Dec 2012 21:55:57 -0800
Subject: [PATCH 144/146] cleanup: combine files that belong together
---
.../src/org/eehouse/android/xw4/NetUtils.java | 77 ------------
.../org/eehouse/android/xw4/RelayMsgSink.java | 57 ---------
.../org/eehouse/android/xw4/RelayService.java | 110 +++++++++++++++++-
3 files changed, 104 insertions(+), 140 deletions(-)
delete mode 100644 xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayMsgSink.java
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetUtils.java
index 75d3d11b0..4e8ee9942 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetUtils.java
@@ -21,21 +21,14 @@
package org.eehouse.android.xw4;
import android.content.Context;
-import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.InetAddress;
import java.net.Socket;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
import javax.net.SocketFactory;
public class NetUtils {
- private static final int MAX_SEND = 1024;
- private static final int MAX_BUF = MAX_SEND - 2;
-
public static final byte PROTOCOL_VERSION = 0;
// from xwrelay.h
public static byte PRX_PUB_ROOMS = 1;
@@ -194,76 +187,6 @@ public class NetUtils {
return msgs;
} // queryRelay
- public static void sendToRelay( Context context,
- HashMap> msgHash )
- {
- // format: total msg lenth: 2
- // number-of-relayIDs: 2
- // for-each-relayid: relayid + '\n': varies
- // message count: 1
- // for-each-message: length: 2
- // message: varies
-
- if ( null != msgHash ) {
- try {
- // Build up a buffer containing everything but the total
- // message length and number of relayIDs in the message.
- ByteArrayOutputStream store =
- new ByteArrayOutputStream( MAX_BUF ); // mem
- DataOutputStream outBuf = new DataOutputStream( store );
- int msgLen = 4; // relayID count + protocol stuff
- int nRelayIDs = 0;
-
- Iterator iter = msgHash.keySet().iterator();
- while ( iter.hasNext() ) {
- String relayID = iter.next();
- int thisLen = 1 + relayID.length(); // string and '\n'
- thisLen += 2; // message count
-
- ArrayList msgs = msgHash.get( relayID );
- for ( byte[] msg : msgs ) {
- thisLen += 2 + msg.length;
- }
-
- if ( msgLen + thisLen > MAX_BUF ) {
- // Need to deal with this case by sending multiple
- // packets. It WILL happen.
- break;
- }
- // got space; now write it
- ++nRelayIDs;
- outBuf.writeBytes( relayID );
- outBuf.write( '\n' );
- outBuf.writeShort( msgs.size() );
- for ( byte[] msg : msgs ) {
- outBuf.writeShort( msg.length );
- outBuf.write( msg );
- }
- msgLen += thisLen;
- }
-
- // Now open a real socket, write size and proto, and
- // copy in the formatted buffer
- Socket socket = makeProxySocket( context, 8000 );
- if ( null != socket ) {
- DataOutputStream outStream =
- new DataOutputStream( socket.getOutputStream() );
- outStream.writeShort( msgLen );
- outStream.writeByte( NetUtils.PROTOCOL_VERSION );
- outStream.writeByte( NetUtils.PRX_PUT_MSGS );
- outStream.writeShort( nRelayIDs );
- outStream.write( store.toByteArray() );
- outStream.flush();
- socket.close();
- }
- } catch ( java.io.IOException ioe ) {
- DbgUtils.loge( ioe );
- }
- } else {
- DbgUtils.logf( "sendToRelay: null msgs" );
- }
- } // sendToRelay
-
private static int sumStrings( final String[] strs )
{
int len = 0;
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayMsgSink.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayMsgSink.java
deleted file mode 100644
index 53e0ccfdd..000000000
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayMsgSink.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
-/*
- * Copyright 2009-2010 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.content.Context;
-import java.util.HashMap;
-import java.util.ArrayList;
-
-import junit.framework.Assert;
-
-import org.eehouse.android.xw4.jni.*;
-
-public class RelayMsgSink extends MultiMsgSink {
-
- private HashMap> m_msgLists = null;
-
- public void send( Context context )
- {
- NetUtils.sendToRelay( context, m_msgLists );
- }
-
- /***** TransportProcs interface *****/
-
- public boolean relayNoConnProc( byte[] buf, String relayID )
- {
- if ( null == m_msgLists ) {
- m_msgLists = new HashMap>();
- }
-
- ArrayList list = m_msgLists.get( relayID );
- if ( list == null ) {
- list = new ArrayList();
- m_msgLists.put( relayID, list );
- }
- list.add( buf );
-
- return true;
- }
-}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayService.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayService.java
index 5da48cd30..bc4d2d179 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayService.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayService.java
@@ -24,18 +24,18 @@ import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
-import javax.net.SocketFactory;
-import java.net.InetAddress;
-import java.net.Socket;
-import java.io.InputStream;
-import java.io.DataInputStream;
-import java.io.OutputStream;
+import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
+import java.net.Socket;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
import org.eehouse.android.xw4.jni.GameSummary;
public class RelayService extends Service {
+ private static final int MAX_SEND = 1024;
+ private static final int MAX_BUF = MAX_SEND - 2;
@Override
public void onCreate()
@@ -114,4 +114,102 @@ public class RelayService extends Service {
}
}
+ private static void sendToRelay( Context context,
+ HashMap> msgHash )
+ {
+ // format: total msg lenth: 2
+ // number-of-relayIDs: 2
+ // for-each-relayid: relayid + '\n': varies
+ // message count: 1
+ // for-each-message: length: 2
+ // message: varies
+
+ if ( null != msgHash ) {
+ try {
+ // Build up a buffer containing everything but the total
+ // message length and number of relayIDs in the message.
+ ByteArrayOutputStream store =
+ new ByteArrayOutputStream( MAX_BUF ); // mem
+ DataOutputStream outBuf = new DataOutputStream( store );
+ int msgLen = 4; // relayID count + protocol stuff
+ int nRelayIDs = 0;
+
+ Iterator iter = msgHash.keySet().iterator();
+ while ( iter.hasNext() ) {
+ String relayID = iter.next();
+ int thisLen = 1 + relayID.length(); // string and '\n'
+ thisLen += 2; // message count
+
+ ArrayList msgs = msgHash.get( relayID );
+ for ( byte[] msg : msgs ) {
+ thisLen += 2 + msg.length;
+ }
+
+ if ( msgLen + thisLen > MAX_BUF ) {
+ // Need to deal with this case by sending multiple
+ // packets. It WILL happen.
+ break;
+ }
+ // got space; now write it
+ ++nRelayIDs;
+ outBuf.writeBytes( relayID );
+ outBuf.write( '\n' );
+ outBuf.writeShort( msgs.size() );
+ for ( byte[] msg : msgs ) {
+ outBuf.writeShort( msg.length );
+ outBuf.write( msg );
+ }
+ msgLen += thisLen;
+ }
+
+ // Now open a real socket, write size and proto, and
+ // copy in the formatted buffer
+ Socket socket = NetUtils.makeProxySocket( context, 8000 );
+ if ( null != socket ) {
+ DataOutputStream outStream =
+ new DataOutputStream( socket.getOutputStream() );
+ outStream.writeShort( msgLen );
+ outStream.writeByte( NetUtils.PROTOCOL_VERSION );
+ outStream.writeByte( NetUtils.PRX_PUT_MSGS );
+ outStream.writeShort( nRelayIDs );
+ outStream.write( store.toByteArray() );
+ outStream.flush();
+ socket.close();
+ }
+ } catch ( java.io.IOException ioe ) {
+ DbgUtils.loge( ioe );
+ }
+ } else {
+ DbgUtils.logf( "sendToRelay: null msgs" );
+ }
+ } // sendToRelay
+
+ private class RelayMsgSink extends MultiMsgSink {
+
+ private HashMap> m_msgLists = null;
+
+ public void send( Context context )
+ {
+ sendToRelay( context, m_msgLists );
+ }
+
+ /***** TransportProcs interface *****/
+
+ public boolean relayNoConnProc( byte[] buf, String relayID )
+ {
+ if ( null == m_msgLists ) {
+ m_msgLists = new HashMap>();
+ }
+
+ ArrayList list = m_msgLists.get( relayID );
+ if ( list == null ) {
+ list = new ArrayList();
+ m_msgLists.put( relayID, list );
+ }
+ list.add( buf );
+
+ return true;
+ }
+ }
+
}
From 1998da45decd6a7452105b03ff7c254110cdfe7a Mon Sep 17 00:00:00 2001
From: Eric House
Date: Fri, 21 Dec 2012 17:14:55 -0800
Subject: [PATCH 145/146] don't save game when it hasn't changed -- when saved
bytes are identical with those we started with.
---
.../eehouse/android/xw4/BoardActivity.java | 5 +--
.../eehouse/android/xw4/jni/JNIThread.java | 34 ++++++++++++-------
2 files changed, 24 insertions(+), 15 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
index c0bb10d0b..698f2144c 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
@@ -1739,8 +1739,9 @@ public class BoardActivity extends XWActivity
}
}
};
- m_jniThread = new JNIThread( m_jniGamePtr, m_gi, m_view,
- m_gameLock, this, handler );
+ m_jniThread =
+ new JNIThread( m_jniGamePtr, stream, m_gi,
+ m_view, m_gameLock, this, handler );
// see http://stackoverflow.com/questions/680180/where-to-stop-\
// destroy-threads-in-android-service-class
m_jniThread.setDaemon( true );
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java
index e39adc389..39858aade 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java
@@ -22,13 +22,14 @@
package org.eehouse.android.xw4.jni;
import android.content.Context;
-import java.lang.InterruptedException;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.Iterator;
-import android.os.Handler;
-import android.os.Message;
import android.graphics.Paint;
import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Message;
+import java.lang.InterruptedException;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.concurrent.LinkedBlockingQueue;
import org.eehouse.android.xw4.R;
import org.eehouse.android.xw4.DbgUtils;
@@ -122,6 +123,7 @@ public class JNIThread extends Thread {
private boolean m_stopped = false;
private boolean m_saveOnStop = false;
private int m_jniGamePtr;
+ private byte[] m_gameAtStart;
private GameLock m_lock;
private Context m_context;
private CurGameInfo m_gi;
@@ -143,10 +145,12 @@ public class JNIThread extends Thread {
Object[] m_args;
}
- public JNIThread( int gamePtr, CurGameInfo gi, SyncedDraw drawer,
- GameLock lock, Context context, Handler handler )
+ public JNIThread( int gamePtr, byte[] gameAtStart, CurGameInfo gi,
+ SyncedDraw drawer, GameLock lock, Context context,
+ Handler handler )
{
m_jniGamePtr = gamePtr;
+ m_gameAtStart = gameAtStart;
m_gi = gi;
m_drawer = drawer;
m_lock = lock;
@@ -286,13 +290,17 @@ public class JNIThread extends Thread {
if ( null != m_newDict ) {
m_gi.dictName = m_newDict;
}
- GameSummary summary = new GameSummary( m_context, m_gi );
- XwJNI.game_summarize( m_jniGamePtr, summary );
byte[] state = XwJNI.game_saveToStream( m_jniGamePtr, m_gi );
- GameUtils.saveGame( m_context, state, m_lock, false );
- DBUtils.saveSummary( m_context, m_lock, summary );
- // There'd better be no way for saveGame above to fail!
- XwJNI.game_saveSucceeded( m_jniGamePtr );
+ if ( Arrays.equals( m_gameAtStart, state ) ) {
+ DbgUtils.logf( "no change in game; can skip saving" );
+ } else {
+ GameSummary summary = new GameSummary( m_context, m_gi );
+ XwJNI.game_summarize( m_jniGamePtr, summary );
+ DBUtils.saveGame( m_context, m_lock, state, false );
+ DBUtils.saveSummary( m_context, m_lock, summary );
+ // There'd better be no way for saveGame above to fail!
+ XwJNI.game_saveSucceeded( m_jniGamePtr );
+ }
}
@SuppressWarnings("fallthrough")
From 2461b526a5411933c229089250cd49f873c8ea5a Mon Sep 17 00:00:00 2001
From: Eric House
Date: Fri, 21 Dec 2012 18:06:27 -0800
Subject: [PATCH 146/146] move check for updates into async task
---
.../android/xw4/UpdateCheckReceiver.java | 206 ++++++++++--------
1 file changed, 120 insertions(+), 86 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/UpdateCheckReceiver.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/UpdateCheckReceiver.java
index 8b69846d2..932f699db 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/UpdateCheckReceiver.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/UpdateCheckReceiver.java
@@ -28,6 +28,7 @@ import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
+import android.os.AsyncTask;
import android.os.SystemClock;
import java.io.File;
import java.util.ArrayList;
@@ -154,92 +155,8 @@ public class UpdateCheckReceiver extends BroadcastReceiver {
}
if ( 0 < params.length() ) {
- HttpPost post = makePost( context, "getUpdates" );
- String json = runPost( post, params );
- if ( null != json ) {
- makeNotificationsIf( context, fromUI, json, pm, packageName,
- dals );
- }
- }
- }
-
- private static void makeNotificationsIf( Context context, boolean fromUI,
- String jstr, PackageManager pm,
- String packageName,
- DictUtils.DictAndLoc[] dals )
- {
- boolean gotOne = false;
- try {
- JSONObject jobj = new JSONObject( jstr );
- if ( null != jobj ) {
- if ( jobj.has( k_APP ) ) {
- JSONObject app = jobj.getJSONObject( k_APP );
- if ( app.has( k_URL ) ) {
- ApplicationInfo ai = pm.getApplicationInfo( packageName, 0);
- String label = pm.getApplicationLabel( ai ).toString();
-
- // If there's a download dir AND an installer
- // app, handle this ourselves. Otherwise just
- // launch the browser
- boolean useBrowser;
- File downloads = DictUtils.getDownloadDir( context );
- if ( null == downloads ) {
- useBrowser = true;
- } else {
- File tmp = new File( downloads,
- "xx" + XWConstants.APK_EXTN );
- useBrowser = !Utils.canInstall( context, tmp );
- }
-
- Intent intent;
- String url = app.getString( k_URL );
- if ( useBrowser ) {
- intent = new Intent( Intent.ACTION_VIEW,
- Uri.parse(url) );
- } else {
- intent = DictImportActivity
- .makeAppDownloadIntent( context, url );
- }
-
- String title =
- Utils.format( context, R.string.new_app_availf, label );
- String body = context.getString( R.string.new_app_avail );
- Utils.postNotification( context, intent, title, body,
- url.hashCode() );
- gotOne = true;
- }
- }
- if ( jobj.has( k_DICTS ) ) {
- JSONArray dicts = jobj.getJSONArray( k_DICTS );
- for ( int ii = 0; ii < dicts.length(); ++ii ) {
- JSONObject dict = dicts.getJSONObject( ii );
- if ( dict.has( k_URL ) && dict.has( k_INDEX ) ) {
- String url = dict.getString( k_URL );
- int index = dict.getInt( k_INDEX );
- DictUtils.DictAndLoc dal = dals[index];
- Intent intent =
- new Intent( context, DictsActivity.class );
- intent.putExtra( NEW_DICT_URL, url );
- intent.putExtra( NEW_DICT_LOC, dal.loc.ordinal() );
- String body =
- Utils.format( context, R.string.new_dict_availf,
- dal.name );
- Utils.postNotification( context, intent,
- R.string.new_dict_avail,
- body, url.hashCode() );
- gotOne = true;
- }
- }
- }
- }
- } catch ( org.json.JSONException jse ) {
- DbgUtils.loge( jse );
- } catch ( PackageManager.NameNotFoundException nnfe ) {
- DbgUtils.loge( nnfe );
- }
-
- if ( !gotOne && fromUI ) {
- Utils.showToast( context, R.string.checkupdates_none_found );
+ new UpdateQueryTask( context, params, fromUI, pm,
+ packageName, dals ).execute();
}
}
@@ -303,4 +220,121 @@ public class UpdateCheckReceiver extends BroadcastReceiver {
false );
}
+ private static class UpdateQueryTask extends AsyncTask {
+ private Context m_context;
+ private JSONObject m_params;
+ private boolean m_fromUI;
+ private PackageManager m_pm;
+ private String m_packageName;
+ private DictUtils.DictAndLoc[] m_dals;
+
+ public UpdateQueryTask( Context context, JSONObject params,
+ boolean fromUI, PackageManager pm,
+ String packageName,
+ DictUtils.DictAndLoc[] dals )
+ {
+ m_context = context;
+ m_params = params;
+ m_fromUI = fromUI;
+ m_pm = pm;
+ m_packageName = packageName;
+ m_dals = dals;
+ }
+
+ @Override protected String doInBackground( Void... unused )
+ {
+ HttpPost post = makePost( m_context, "getUpdates" );
+ String json = runPost( post, m_params );
+ return json;
+ }
+
+ @Override protected void onPostExecute( String json )
+ {
+ if ( null != json ) {
+ makeNotificationsIf( json );
+ }
+ }
+
+ private void makeNotificationsIf( String jstr )
+ {
+ boolean gotOne = false;
+ try {
+ JSONObject jobj = new JSONObject( jstr );
+ if ( null != jobj ) {
+ if ( jobj.has( k_APP ) ) {
+ JSONObject app = jobj.getJSONObject( k_APP );
+ if ( app.has( k_URL ) ) {
+ ApplicationInfo ai =
+ m_pm.getApplicationInfo( m_packageName, 0);
+ String label = m_pm.getApplicationLabel( ai ).toString();
+
+ // If there's a download dir AND an installer
+ // app, handle this ourselves. Otherwise just
+ // launch the browser
+ boolean useBrowser;
+ File downloads = DictUtils.getDownloadDir( m_context );
+ if ( null == downloads ) {
+ useBrowser = true;
+ } else {
+ File tmp = new File( downloads,
+ "xx" + XWConstants.APK_EXTN );
+ useBrowser = !Utils.canInstall( m_context, tmp );
+ }
+
+ Intent intent;
+ String url = app.getString( k_URL );
+ if ( useBrowser ) {
+ intent = new Intent( Intent.ACTION_VIEW,
+ Uri.parse(url) );
+ } else {
+ intent = DictImportActivity
+ .makeAppDownloadIntent( m_context, url );
+ }
+
+ String title =
+ Utils.format( m_context, R.string.new_app_availf,
+ label );
+ String body =
+ m_context.getString( R.string.new_app_avail );
+ Utils.postNotification( m_context, intent, title,
+ body, url.hashCode() );
+ gotOne = true;
+ }
+ }
+ if ( jobj.has( k_DICTS ) ) {
+ JSONArray dicts = jobj.getJSONArray( k_DICTS );
+ for ( int ii = 0; ii < dicts.length(); ++ii ) {
+ JSONObject dict = dicts.getJSONObject( ii );
+ if ( dict.has( k_URL ) && dict.has( k_INDEX ) ) {
+ String url = dict.getString( k_URL );
+ int index = dict.getInt( k_INDEX );
+ DictUtils.DictAndLoc dal = m_dals[index];
+ Intent intent =
+ new Intent( m_context, DictsActivity.class );
+ intent.putExtra( NEW_DICT_URL, url );
+ intent.putExtra( NEW_DICT_LOC, dal.loc.ordinal() );
+ String body =
+ Utils.format( m_context,
+ R.string.new_dict_availf,
+ dal.name );
+ Utils.postNotification( m_context, intent,
+ R.string.new_dict_avail,
+ body, url.hashCode() );
+ gotOne = true;
+ }
+ }
+ }
+ }
+ } catch ( org.json.JSONException jse ) {
+ DbgUtils.loge( jse );
+ } catch ( PackageManager.NameNotFoundException nnfe ) {
+ DbgUtils.loge( nnfe );
+ }
+
+ if ( !gotOne && m_fromUI ) {
+ Utils.showToast( m_context, R.string.checkupdates_none_found );
+ }
+ }
+ }
+
}