Merge branch 'android_branch' into send_in_background

This commit is contained in:
eehouse@eehouse.org 2011-12-20 17:34:26 -08:00 committed by Andy2
commit abd6727b10
14 changed files with 159 additions and 112 deletions

View file

@ -22,7 +22,7 @@
to come from a domain that you own or have control over. -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.eehouse.android.xw4"
android:versionCode="31"
android:versionCode="32"
android:versionName="@string/app_version"
>
@ -43,7 +43,7 @@
<activity android:name="GamesList"
android:label="@string/title_games_list"
android:launchMode="singleTop"
android:launchMode="standard"
android:configChanges="keyboardHidden|orientation"
>
<intent-filter>

View file

@ -8,11 +8,13 @@
<TextView android:id="@+id/item_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:gravity="left"
/>
<TextView android:id="@+id/item_score"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:gravity="right"
/>
</LinearLayout>

View file

@ -6,27 +6,13 @@
</head>
<body>
<b>Crosswords 4.4 beta 39 release</b>
<b>Crosswords 4.4 beta 40 release</b>
<ul>
<li>Offer choice between SMS and email for sending invitations</li>
<li>Add "email author" menuitem to Games List screen. Please
do!</li>
<li>Enable pinch-to-zoom for board</li>
<li>Improve handling of invitations and move notifications received</li>
<li>Improve wordlist browser to filter by size, have larger
text, and not barf when given empty wordlist</li>
<li>Add value/letter toggle button since space isn't so precious
now (and remove menuitem)</li>
<li>Add Setting checkbox to disable crosshairs</li>
<li>Replace Restore menus in Settings with buttons</li>
<li>Fix problem with text color in word lookup dialog on HTC
MyTouch</li>
<li>Make undo button easier to get to</li>
</ul>
<p>Please remember that this is beta software. Please let me know (at

View file

@ -3,7 +3,7 @@
<!-- Resources in this file do not require localization -->
<resources>
<string name="app_version">4.4 beta 39</string>
<string name="app_version">4.4 beta 40</string>
<!-- prefs keys -->
<string name="key_color_tiles">key_color_tiles</string>

View file

@ -525,8 +525,7 @@
<string name="button_trade_commit">Commit exchange</string>
<string name="button_trade_cancel">Cancel exchange</string>
<string name="entering_trade">Tap to select tiles...</string>
<string name="entering_trade">Tap tiles to select...</string>
<!-- Bonus value hint that's displayed in gray text in the colored
@ -1199,9 +1198,9 @@
<!-- This is the body of the text version of the invitation. A URL
is created with parameters describing the game and
substituted for "%1$s".-->
<string name="invite_txtf">Play Crosswords? Join this
game: %1$s . (But install Crosswords first if you haven\'t:
http://eehouse.org/market_redir.php ).</string>
<string name="invite_txtf">Play Crosswords? Join this game: %1$s
. (But install Crosswords http://eehouse.org/market_redir.php
first if you haven\'t.)</string>
<!-- When I've created the invitation, in text or html, I ask
Android to launch an app that can send it, typically an email

View file

@ -670,7 +670,7 @@ public class BoardActivity extends XWActivity
if ( DlgDelegate.DISMISS_BUTTON != which ) {
GameUtils.launchInviteActivity( BoardActivity.this,
DlgDelegate.EMAIL_BTN == which,
m_room,
m_room, null,
m_gi.dictLang,
m_gi.nPlayers );
}

View file

@ -29,7 +29,7 @@ public class DBHelper extends SQLiteOpenHelper {
public static final String TABLE_NAME_SUM = "summaries";
public static final String TABLE_NAME_OBITS = "obits";
private static final String DB_NAME = "xwdb";
private static final int DB_VERSION = 10;
private static final int DB_VERSION = 11;
public static final String GAME_NAME = "GAME_NAME";
public static final String NUM_MOVES = "NUM_MOVES";
@ -55,6 +55,7 @@ public class DBHelper extends SQLiteOpenHelper {
public static final String CONTYPE = "CONTYPE";
public static final String SERVERROLE = "SERVERROLE";
public static final String ROOMNAME = "ROOMNAME";
public static final String INVITEID = "INVITEID";
public static final String RELAYID = "RELAYID";
public static final String SEED = "SEED";
public static final String SMSPHONE = "SMSPHONE";
@ -85,6 +86,7 @@ public class DBHelper extends SQLiteOpenHelper {
+ SERVERROLE + " INTEGER,"
+ CONTYPE + " INTEGER,"
+ ROOMNAME + " TEXT,"
+ INVITEID + " TEXT,"
+ RELAYID + " TEXT,"
+ SEED + " INTEGER,"
+ DICTLANG + " INTEGER,"
@ -147,6 +149,9 @@ public class DBHelper extends SQLiteOpenHelper {
db.execSQL( "ALTER TABLE " + TABLE_NAME_SUM +
" ADD COLUMN " + DICTLIST + " TEXT;" );
case 10:
db.execSQL( "ALTER TABLE " + TABLE_NAME_SUM +
" ADD COLUMN " + INVITEID + " TEXT;" );
case 11:
// nothing yet
break;
default:

View file

@ -24,6 +24,7 @@ import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.Cursor;
import android.net.Uri;
import java.util.StringTokenizer;
import android.content.ContentValues;
import java.util.ArrayList;
@ -37,6 +38,7 @@ import org.eehouse.android.xw4.jni.*;
public class DBUtils {
public static final int ROWID_NOTFOUND = -1;
private static final String DICTS_SEP = ",";
@ -209,6 +211,12 @@ public class DBUtils {
public static void saveSummary( Context context, GameUtils.GameLock lock,
GameSummary summary )
{
saveSummary( context, lock, summary, null );
}
public static void saveSummary( Context context, GameUtils.GameLock lock,
GameSummary summary, String inviteID )
{
Assert.assertTrue( lock.canWrite() );
long rowid = lock.getRowid();
@ -233,6 +241,9 @@ public class DBUtils {
values.put( DBHelper.GAME_OVER, summary.gameOver );
values.put( DBHelper.DICTLIST, summary.dictNames(DICTS_SEP) );
values.put( DBHelper.HASMSGS, summary.pendingMsgLevel );
if ( null != inviteID ) {
values.put( DBHelper.INVITEID, inviteID );
}
if ( null != summary.scores ) {
StringBuffer sb = new StringBuffer();
@ -363,7 +374,7 @@ public class DBUtils {
public static long getRowIDFor( Context context, String relayID )
{
long result = -1;
long result = ROWID_NOTFOUND;
initDB( context );
synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
@ -380,18 +391,17 @@ public class DBUtils {
return result;
}
public static long getRowIDForOpen( Context context, String room,
int lang, int nPlayers )
public static long getRowIDForOpen( Context context, NetLaunchInfo nli )
{
long result = -1;
long result = ROWID_NOTFOUND;
initDB( context );
synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
String[] columns = { ROW_ID };
String selection = DBHelper.ROOMNAME + "='" + room + "' AND "
// + DBHelper.INVITEID + "='" + inviteID + "' AND "
+ DBHelper.DICTLANG + "=" + lang + " AND "
+ DBHelper.NUM_PLAYERS + "=" + nPlayers;
String selection = DBHelper.ROOMNAME + "='" + nli.room + "' AND "
+ DBHelper.INVITEID + "='" + nli.inviteID + "' AND "
+ DBHelper.DICTLANG + "=" + nli.lang + " AND "
+ DBHelper.NUM_PLAYERS + "=" + nli.nPlayers;
Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
selection, null, null, null, null );
if ( 1 == cursor.getCount() && cursor.moveToFirst() ) {
@ -403,6 +413,12 @@ public class DBUtils {
return result;
}
public static boolean isNewInvite( Context context, Uri data )
{
NetLaunchInfo nli = new NetLaunchInfo( data );
return null != nli && -1 == getRowIDForOpen( context, nli );
}
public static String[] getRelayIDs( Context context, boolean noMsgs )
{
String[] result = null;

View file

@ -41,7 +41,8 @@ public class DispatchNotify extends Activity {
void HandleInvite( final Uri invite );
}
private static HashSet<Activity> s_running = new HashSet<Activity>();
private static HashSet<HandleRelaysIface> s_running =
new HashSet<HandleRelaysIface>();
private static HandleRelaysIface s_handler;
@Override
@ -57,9 +58,13 @@ public class DispatchNotify extends Activity {
if ( !tryHandle( relayIDs ) ) {
mustLaunch = true;
}
} else if ( null != data ) {
if ( !tryHandle( data ) ) {
mustLaunch = true;
} else if ( null != data ) {
if ( DBUtils.isNewInvite( this, data ) ) {
if ( !tryHandle( data ) ) {
mustLaunch = true;
}
} else {
DbgUtils.logf( "DispatchNotify: dropping duplicate invite" );
}
}
@ -67,22 +72,19 @@ public class DispatchNotify extends Activity {
DbgUtils.logf( "DispatchNotify: nothing running" );
Intent intent = new Intent( this, GamesList.class );
/* Flags. Tried Intent.FLAG_ACTIVITY_NEW_TASK. I don't
* remember what it fixes, but what it breaks is easy to
* duplicate. Launch Crosswords from the home screen making
* sure it's the only instance running. Get a networked game
* going, and with BoardActivity frontmost check the relay and
* select a relay notification. New BoardActivity will come
* up, but if you hit home button then Crosswords icon you're
* back to games list. Hit back button and you're back to
* BoardActivity, and back from there back to GamesList.
* That's because a new activity came up from the activity
* below thanks to the flag.
*/
// 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 NO See above
);
| Intent.FLAG_ACTIVITY_NEW_TASK );
if ( null != relayIDs ) {
intent.putExtra( RELAYIDS_EXTRA, relayIDs );
} else if ( null != data ) {
@ -98,12 +100,16 @@ public class DispatchNotify extends Activity {
public static void SetRunning( Activity running )
{
s_running.add( running );
if ( running instanceof HandleRelaysIface ) {
s_running.add( (HandleRelaysIface)running );
}
}
public static void ClearRunning( Activity running )
{
s_running.remove( running );
if ( running instanceof HandleRelaysIface ) {
s_running.remove( (HandleRelaysIface)running );
}
}
public static void SetRelayIDsHandler( HandleRelaysIface iface )
@ -119,13 +125,9 @@ public class DispatchNotify extends Activity {
s_handler.HandleInvite( data );
handled = true;
} else {
for ( Activity activity : s_running ) {
if ( activity instanceof DispatchNotify.HandleRelaysIface ) {
DispatchNotify.HandleRelaysIface iface =
(DispatchNotify.HandleRelaysIface)activity;
iface.HandleInvite( data );
handled = true;
}
for ( HandleRelaysIface iface : s_running ) {
iface.HandleInvite( data );
handled = true;
}
}
return handled;
@ -139,13 +141,9 @@ public class DispatchNotify extends Activity {
s_handler.HandleRelaysIDs( relayIDs );
handled = true;
} else {
for ( Activity activity : s_running ) {
if ( activity instanceof DispatchNotify.HandleRelaysIface ) {
DispatchNotify.HandleRelaysIface iface =
(DispatchNotify.HandleRelaysIface)activity;
iface.HandleRelaysIDs( relayIDs );
handled = true;
}
for ( HandleRelaysIface iface : s_running ) {
iface.HandleRelaysIDs( relayIDs );
handled = true;
}
}
return handled;

View file

@ -48,6 +48,7 @@ import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole;
public class GameUtils {
public static final String INVITED = "invited";
private static Random s_random = new Random();
// Implements read-locks and write-locks per game. A read lock is
// obtainable when other read locks are granted but not when a
@ -171,7 +172,7 @@ public class GameUtils {
* basis for a new one.
*/
public static GameLock resetGame( Context context, GameLock lockSrc,
GameLock lockDest )
GameLock lockDest, boolean juggle )
{
CurGameInfo gi = new CurGameInfo( context );
CommsAddrRec addr = null;
@ -198,6 +199,10 @@ public class GameUtils {
CommonPrefs.get( context ), dictNames,
pairs.m_bytes, pairs.m_paths, gi.langName() );
if ( juggle ) {
gi.juggle();
}
if ( null != addr ) {
XwJNI.comms_setAddr( gamePtr, addr );
}
@ -217,7 +222,7 @@ public class GameUtils {
{
GameLock lock = new GameLock( rowidIn, true ).lock();
tellRelayDied( context, lock, true );
resetGame( context, lock, lock );
resetGame( context, lock, lock, false );
lock.unlock();
}
@ -264,8 +269,9 @@ 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 );
GameLock lockDest = resetGame( context, lockSrc, null, juggle );
long rowid = lockDest.getRowid();
lockDest.unlock();
lockSrc.unlock();
@ -374,9 +380,9 @@ public class GameUtils {
return rowid;
}
public static long makeNewNetGame( Context context, String room,
int[] lang, int nPlayersT,
int nPlayersH )
public static long makeNewNetGame( Context context, String room,
String inviteID, int[] lang,
int nPlayersT, int nPlayersH )
{
long rowid = -1;
CommsAddrRec addr = new CommsAddrRec( context );
@ -393,32 +399,35 @@ public class GameUtils {
rowid = saveNew( context, gi );
GameLock lock = new GameLock( rowid, true ).lock();
applyChanges( context, gi, addr, lock, false );
applyChanges( context, gi, addr, inviteID, lock, false );
lock.unlock();
return rowid;
}
public static long makeNewNetGame( Context context, String room,
int lang, int nPlayers )
String inviteID, int lang, int nPlayers )
{
int[] langarr = { lang };
return makeNewNetGame( context, room, langarr, nPlayers, 1 );
return makeNewNetGame( context, room, inviteID, langarr, nPlayers, 1 );
}
public static long makeNewNetGame( Context context, NetLaunchInfo info )
{
return makeNewNetGame( context, info.room, info.lang,
return makeNewNetGame( context, info.room, info.inviteID, info.lang,
info.nPlayers );
}
public static void launchInviteActivity( Context context,
boolean choseEmail,
String room,
String room, String inviteID,
int lang, int nPlayers )
{
Random random = new Random();
Uri gameUri = NetLaunchInfo.makeLaunchUri( context, room,
if ( null == inviteID ) {
inviteID = makeRandomID();
}
Uri gameUri = NetLaunchInfo.makeLaunchUri( context, room, inviteID,
lang, nPlayers );
if ( null != gameUri ) {
@ -657,8 +666,15 @@ public class GameUtils {
}
public static void applyChanges( Context context, CurGameInfo gi,
CommsAddrRec car, GameLock lock,
CommsAddrRec car, GameLock lock,
boolean forceNew )
{
applyChanges( context, gi, car, null, lock, forceNew );
}
public static void applyChanges( Context context, CurGameInfo gi,
CommsAddrRec car, String inviteID,
GameLock lock, boolean forceNew )
{
// This should be a separate function, commitChanges() or
// somesuch. But: do we have a way to save changes to a gi
@ -697,7 +713,7 @@ public class GameUtils {
GameSummary summary = new GameSummary( context, gi );
XwJNI.game_summarize( gamePtr, summary );
DBUtils.saveSummary( context, lock, summary );
DBUtils.saveSummary( context, lock, summary, inviteID );
XwJNI.game_dispose( gamePtr );
} // applyChanges
@ -710,6 +726,15 @@ public class GameUtils {
activity.startActivity( intent );
}
public static String makeRandomID()
{
int rint = 0;
while ( 0 == rint ) {
rint = s_random.nextInt();
}
return String.format( "%X", rint ).substring( 0, 4 );
}
private static void tellRelayDied( Context context, GameLock lock,
boolean informNow )
{

View file

@ -68,7 +68,7 @@ public class GamesList extends XWListActivity
private static final int DELETE_GAME_ACTION = 3;
private static final int DELETE_ALL_ACTION = 4;
private static final int SYNC_MENU_ACTION = 5;
private static final int DUPE_GAME_ACTION = 6;
private static final int NEW_FROM_ACTION = 6;
private GameListAdapter m_adapter;
private String m_missingDict;
@ -245,6 +245,9 @@ public class GamesList extends XWListActivity
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate( savedInstanceState );
// scary, but worth playing with:
// Assert.assertTrue( isTaskRoot() );
getBundledData( savedInstanceState );
m_handler = new Handler();
@ -375,7 +378,7 @@ public class GamesList extends XWListActivity
} );
}
public void HandleInvite( final Uri invite )
public void HandleInvite( Uri invite )
{
final NetLaunchInfo nli = new NetLaunchInfo( invite );
if ( nli.isValid() ) {
@ -431,7 +434,7 @@ public class GamesList extends XWListActivity
case SYNC_MENU_ACTION:
doSyncMenuitem();
break;
case DUPE_GAME_ACTION:
case NEW_FROM_ACTION:
long newid = GameUtils.dupeGame( GamesList.this, m_rowid );
if ( null != m_adapter ) {
m_adapter.inval( newid );
@ -584,7 +587,7 @@ public class GamesList extends XWListActivity
case R.id.list_item_new_from:
showNotAgainDlgThen( R.string.not_again_newfrom,
R.string.key_notagain_newfrom,
DUPE_GAME_ACTION );
NEW_FROM_ACTION );
break;
case R.id.list_item_copy:
@ -682,10 +685,9 @@ public class GamesList extends XWListActivity
private void startNewNetGame( NetLaunchInfo info )
{
long rowid = DBUtils.getRowIDForOpen( this, info.room, info.lang,
info.nPlayers );
long rowid = DBUtils.getRowIDForOpen( this, info );
if ( -1 == rowid ) { // doesn't exist yet
if ( DBUtils.ROWID_NOTFOUND == rowid ) {
rowid = GameUtils.makeNewNetGame( this, info );
GameUtils.launchGame( this, rowid, true );
} else {

View file

@ -31,11 +31,13 @@ import org.eehouse.android.xw4.jni.CommonPrefs;
public class NetLaunchInfo {
public String room;
public String inviteID;
public int lang;
public int nPlayers;
private static final String LANG = "netlaunchinfo_lang";
private static final String ROOM = "netlaunchinfo_room";
private static final String INVITEID = "netlaunchinfo_inviteid";
private static final String NPLAYERS = "netlaunchinfo_nplayers";
private static final String VALID = "netlaunchinfo_valid";
@ -45,6 +47,7 @@ public class NetLaunchInfo {
{
bundle.putInt( LANG, lang );
bundle.putString( ROOM, room );
bundle.putString( INVITEID, inviteID );
bundle.putInt( NPLAYERS, nPlayers );
bundle.putBoolean( VALID, m_valid );
}
@ -53,31 +56,18 @@ public class NetLaunchInfo {
{
lang = bundle.getInt( LANG );
room = bundle.getString( ROOM );
inviteID = bundle.getString( INVITEID );
nPlayers = bundle.getInt( NPLAYERS );
m_valid = bundle.getBoolean( VALID );
}
public static Uri makeLaunchUri( Context context, String room,
int lang, int nPlayers )
{
Builder ub = new Builder();
ub.scheme( "http" );
String format = context.getString( R.string.game_url_pathf );
ub.path( String.format( format,
CommonPrefs.getDefaultRedirHost( context ) ) );
ub.appendQueryParameter( "lang", String.format("%d", lang ) );
ub.appendQueryParameter( "np", String.format( "%d", nPlayers ) );
ub.appendQueryParameter( "room", room );
return ub.build();
}
public NetLaunchInfo( Uri data )
{
m_valid = false;
if ( null != data ) {
try {
room = data.getQueryParameter( "room" );
inviteID = data.getQueryParameter( "id" );
String langStr = data.getQueryParameter( "lang" );
lang = Integer.decode( langStr );
String np = data.getQueryParameter( "np" );
@ -89,6 +79,22 @@ public class NetLaunchInfo {
}
}
public static Uri makeLaunchUri( Context context, String room,
String inviteID, int lang, int nPlayers )
{
Builder ub = new Builder();
ub.scheme( "http" );
String format = context.getString( R.string.game_url_pathf );
ub.path( String.format( format,
CommonPrefs.getDefaultRedirHost( context ) ) );
ub.appendQueryParameter( "lang", String.format("%d", lang ) );
ub.appendQueryParameter( "np", String.format( "%d", nPlayers ) );
ub.appendQueryParameter( "room", room );
ub.appendQueryParameter( "id", inviteID );
return ub.build();
}
public boolean isValid()
{
return m_valid;

View file

@ -116,14 +116,16 @@ public class NewGameActivity extends XWActivity {
boolean choseEmail )
{
String room = null;
String inviteID = null;
long rowid;
int[] lang = {0};
final int nPlayers = 2; // hard-coded for no-configure case
if ( networked ) {
Random random = new Random();
room = String.format( "%X", random.nextInt() ).substring( 0, 4 );
rowid = GameUtils.makeNewNetGame( this, room, lang, nPlayers, 1 );
room = GameUtils.makeRandomID();
inviteID = GameUtils.makeRandomID();
rowid = GameUtils.makeNewNetGame( this, room, inviteID, lang,
nPlayers, 1 );
} else {
rowid = GameUtils.saveNew( this, new CurGameInfo( this ) );
}
@ -131,8 +133,8 @@ public class NewGameActivity extends XWActivity {
if ( launch ) {
GameUtils.launchGame( this, rowid, networked );
if ( networked ) {
GameUtils.launchInviteActivity( this, choseEmail, room,
lang[0], nPlayers );
GameUtils.launchInviteActivity( this, choseEmail, room,
inviteID, lang[0], nPlayers );
}
} else {
GameUtils.doConfig( this, rowid, GameConfig.class );

View file

@ -9,6 +9,12 @@ $host = "10.0.2.2";
$lang = $_REQUEST["lang"];
$room = $_REQUEST["room"];
$np = $_REQUEST["np"];
$id = $_REQUEST["id"];
$content = "0; url=$scheme://$host?room=$room&lang=$lang&np=$np";
if ( $id != "" ) {
$content .= "&id=$id";
}
print <<<EOF
@ -17,7 +23,7 @@ print <<<EOF
<head>
<title>Crosswords SMS redirect</title>
<meta http-equiv="REFRESH"
content="0;url=$scheme://$host?room=$room&lang=$lang&np=$np">
content="$content">
</head>
<body>