diff --git a/xwords4/android/XWords4/res/values/strings.xml b/xwords4/android/XWords4/res/values/strings.xml
index f47737116..ebd8ed481 100644
--- a/xwords4/android/XWords4/res/values/strings.xml
+++ b/xwords4/android/XWords4/res/values/strings.xml
@@ -389,11 +389,18 @@
Substitute dictionary (wordcount)
Substitute
- Unable to open game because no %s
- dictionary found.
- Unable to open game because
- dictionary %1$s not found. You can download a replacement or
- substitute another %2$s dictionary.
+ Close game
+ A dictionary this game is using has
+ disappeared. (Usually this means it\'s on an external card that
+ is no longer available.)
+ Unable to open game \"%1$s\" because no
+ %2$s dictionary found. (It may have been deleted, or stored on
+ an external card that is no longer available.)
+ Unable to open game \"%1$s\" because
+ dictionary %2$s not found. (It may have been deleted, or stored
+ on an external card that is no longer available.) You can
+ download a replacement or substitute another %3$s
+ dictionary.
Password for \"%s\":
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 a79c25951..436809680 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
@@ -38,6 +38,7 @@ import android.app.Dialog;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
+import android.content.DialogInterface.OnDismissListener;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.EditText;
@@ -80,7 +81,7 @@ public class BoardActivity extends XWActivity
private int m_jniGamePtr;
private GameUtils.GameLock m_gameLock;
private CurGameInfo m_gi;
- CommsTransport m_xport;
+ private CommsTransport m_xport;
private Handler m_handler = null;
private TimerRunnable[] m_timers;
private Runnable m_screenTimer;
@@ -1044,89 +1045,96 @@ public class BoardActivity extends XWActivity
private void loadGame()
{
if ( 0 == m_jniGamePtr ) {
- Assert.assertNull( m_gameLock );
- m_gameLock = new GameUtils.GameLock( m_rowid, true ).lock();
-
- byte[] stream = GameUtils.savedGame( this, m_gameLock );
- XwJNI.gi_from_stream( m_gi, stream );
-
String[] dictNames = m_gi.dictNames();
GameUtils.DictPairs pairs = GameUtils.openDicts( this, dictNames );
- String langName = m_gi.langName();
- m_jniGamePtr = XwJNI.initJNI();
- if ( m_gi.serverRole != DeviceRole.SERVER_STANDALONE ) {
- m_xport = new CommsTransport( m_jniGamePtr, this, this,
- m_gi.serverRole );
- }
+ if ( pairs.anyMissing( dictNames ) ) {
+ showDictGoneFinish();
+ } else {
- CommonPrefs cp = CommonPrefs.get( this );
- if ( null == stream ||
- ! XwJNI.game_makeFromStream( m_jniGamePtr, stream,
- m_gi, dictNames, pairs.m_bytes,
- pairs.m_paths, langName, m_utils,
- m_jniu, m_view, cp, m_xport ) ) {
- XwJNI.game_makeNewGame( m_jniGamePtr, m_gi, m_utils, m_jniu,
- m_view, cp, m_xport, dictNames,
- pairs.m_bytes, pairs.m_paths,
- langName );
- }
+ String langName = m_gi.langName();
- m_jniThread = new
- JNIThread( m_jniGamePtr, m_gi, m_view, m_gameLock, this,
- new Handler() {
- public void handleMessage( Message msg ) {
- switch( msg.what ) {
- case JNIThread.DRAW:
- m_view.invalidate();
- break;
- case JNIThread.DIALOG:
- m_dlgBytes = (String)msg.obj;
- m_dlgTitle = msg.arg1;
- showDialog( DLG_OKONLY );
- break;
- case JNIThread.QUERY_ENDGAME:
- showDialog( QUERY_ENDGAME );
- break;
- case JNIThread.TOOLBAR_STATES:
- if ( null != m_jniThread ) {
- m_gsi = m_jniThread.getGameStateInfo();
- updateToolbar();
+ Assert.assertNull( m_gameLock );
+ m_gameLock = new GameUtils.GameLock( m_rowid, true ).lock();
+
+ byte[] stream = GameUtils.savedGame( this, m_gameLock );
+ XwJNI.gi_from_stream( m_gi, stream );
+
+ m_jniGamePtr = XwJNI.initJNI();
+
+ if ( m_gi.serverRole != DeviceRole.SERVER_STANDALONE ) {
+ m_xport = new CommsTransport( m_jniGamePtr, this, this,
+ m_gi.serverRole );
+ }
+
+ CommonPrefs cp = CommonPrefs.get( this );
+ if ( null == stream ||
+ ! XwJNI.game_makeFromStream( m_jniGamePtr, stream,
+ m_gi, dictNames, pairs.m_bytes,
+ pairs.m_paths, langName, m_utils,
+ m_jniu, m_view, cp, m_xport ) ) {
+ XwJNI.game_makeNewGame( m_jniGamePtr, m_gi, m_utils, m_jniu,
+ m_view, cp, m_xport, dictNames,
+ pairs.m_bytes, pairs.m_paths,
+ langName );
+ }
+
+ m_jniThread = new
+ JNIThread( m_jniGamePtr, m_gi, m_view, m_gameLock, this,
+ new Handler() {
+ public void handleMessage( Message msg ) {
+ switch( msg.what ) {
+ case JNIThread.DRAW:
+ m_view.invalidate();
+ break;
+ case JNIThread.DIALOG:
+ m_dlgBytes = (String)msg.obj;
+ m_dlgTitle = msg.arg1;
+ showDialog( DLG_OKONLY );
+ break;
+ case JNIThread.QUERY_ENDGAME:
+ showDialog( QUERY_ENDGAME );
+ break;
+ case JNIThread.TOOLBAR_STATES:
+ if ( null != m_jniThread ) {
+ m_gsi = m_jniThread.getGameStateInfo();
+ updateToolbar();
+ }
+ break;
}
- break;
}
- }
- } );
- // see http://stackoverflow.com/questions/680180/where-to-stop-\
- // destroy-threads-in-android-service-class
- m_jniThread.setDaemon( true );
- m_jniThread.start();
+ } );
+ // see http://stackoverflow.com/questions/680180/where-to-stop-\
+ // destroy-threads-in-android-service-class
+ m_jniThread.setDaemon( true );
+ m_jniThread.start();
- m_view.startHandling( this, m_jniThread, m_jniGamePtr, m_gi );
- if ( null != m_xport ) {
- m_xport.setReceiver( m_jniThread );
- }
- m_jniThread.handle( JNICmd.CMD_START );
+ m_view.startHandling( this, m_jniThread, m_jniGamePtr, m_gi );
+ if ( null != m_xport ) {
+ m_xport.setReceiver( m_jniThread );
+ }
+ m_jniThread.handle( JNICmd.CMD_START );
- if ( !CommonPrefs.getHideTitleBar( this ) ) {
- setTitle( GameUtils.getName( this, m_rowid ) );
- }
- m_toolbar = new Toolbar( this );
+ if ( !CommonPrefs.getHideTitleBar( this ) ) {
+ setTitle( GameUtils.getName( this, m_rowid ) );
+ }
+ m_toolbar = new Toolbar( this );
- populateToolbar();
+ populateToolbar();
- int flags = DBUtils.getMsgFlags( this, m_rowid );
- if ( 0 != (GameSummary.MSG_FLAGS_CHAT & flags) ) {
- startChatActivity();
- }
- if ( 0 != (GameSummary.MSG_FLAGS_GAMEOVER & flags) ) {
- m_jniThread.handle( JNIThread.JNICmd.CMD_POST_OVER );
- }
- if ( 0 != flags ) {
- DBUtils.setMsgFlags( m_rowid, GameSummary.MSG_FLAGS_NONE );
- }
+ int flags = DBUtils.getMsgFlags( this, m_rowid );
+ if ( 0 != (GameSummary.MSG_FLAGS_CHAT & flags) ) {
+ startChatActivity();
+ }
+ if ( 0 != (GameSummary.MSG_FLAGS_GAMEOVER & flags) ) {
+ m_jniThread.handle( JNIThread.JNICmd.CMD_POST_OVER );
+ }
+ if ( 0 != flags ) {
+ DBUtils.setMsgFlags( m_rowid, GameSummary.MSG_FLAGS_NONE );
+ }
- trySendChats();
+ trySendChats();
+ }
}
} // loadGame
@@ -1209,9 +1217,9 @@ public class BoardActivity extends XWActivity
});
} // populateToolbar
- private DialogInterface.OnDismissListener makeODLforBlocking( final int id )
+ private OnDismissListener makeODLforBlocking( final int id )
{
- return new DialogInterface.OnDismissListener() {
+ return new OnDismissListener() {
public void onDismiss( DialogInterface di ) {
releaseIfBlocking();
removeDialog( id );
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 6901d3d7f..3cf294cf9 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictsActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictsActivity.java
@@ -55,7 +55,8 @@ import org.eehouse.android.xw4.jni.JNIUtilsImpl;
import org.eehouse.android.xw4.jni.CommonPrefs;
public class DictsActivity extends ExpandableListActivity
- implements View.OnClickListener, XWListItem.DeleteCallback {
+ implements View.OnClickListener, XWListItem.DeleteCallback,
+ SDCardWatcher.SDCardNotifiee {
private static final String DICT_DOLAUNCH = "do_launch";
private static final String DICT_LANG_EXTRA = "use_lang";
@@ -75,9 +76,10 @@ public class DictsActivity extends ExpandableListActivity
private XWListItem m_rowView;
GameUtils.DictLoc m_moveFromLoc;
GameUtils.DictLoc m_moveToLoc;
- String m_moveName;
+ private SDCardWatcher m_cardWatcher;
+ private String m_moveName;
- LayoutInflater m_factory;
+ private LayoutInflater m_factory;
private class DictListAdapter implements ExpandableListAdapter {
private Context m_context;
@@ -331,10 +333,17 @@ public class DictsActivity extends ExpandableListActivity
protected void onResume()
{
super.onResume();
+ m_cardWatcher = new SDCardWatcher( this, this );
mkListAdapter();
expandGroups();
}
+ protected void onPause() {
+ m_cardWatcher.close();
+ m_cardWatcher = null;
+ super.onPause();
+ }
+
public void onClick( View v )
{
askStartDownload( 0, null );
@@ -429,7 +438,7 @@ public class DictsActivity extends ExpandableListActivity
showDialog( MOVE_DICT );
}
- // DeleteCallback interface
+ // XWListItem.DeleteCallback interface
public void deleteCalled( int myPosition, final String dict )
{
int code = DictLangCache.getDictLangCode( this, dict );
@@ -457,6 +466,13 @@ public class DictsActivity extends ExpandableListActivity
m_delegate.showConfirmThen( msg, action );
}
+ // SDCardWatcher.SDCardNotifiee interface
+ public void cardMounted()
+ {
+ mkListAdapter();
+ expandGroups();
+ }
+
private void deleteDict( String dict )
{
GameUtils.deleteDict( this, dict );
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 67e3a3193..abc2ee79f 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DlgDelegate.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DlgDelegate.java
@@ -40,7 +40,8 @@ public class DlgDelegate {
public static final int DIALOG_NOTAGAIN = 3;
public static final int CONFIRM_THEN = 4;
public static final int TEXT_OR_HTML_THEN = 5;
- public static final int DIALOG_LAST = TEXT_OR_HTML_THEN;
+ public static final int DLG_DICTGONE = 6;
+ public static final int DIALOG_LAST = DLG_DICTGONE;
private int m_msgID;
private String m_msg;
@@ -78,6 +79,9 @@ public class DlgDelegate {
case TEXT_OR_HTML_THEN:
dialog = createHtmlThenDialog();
break;
+ case DLG_DICTGONE:
+ dialog = createDictGoneDialog();
+ break;
}
return dialog;
}
@@ -141,6 +145,11 @@ public class DlgDelegate {
m_activity.showDialog( DIALOG_OKONLY );
}
+ public void showDictGoneFinish()
+ {
+ m_activity.showDialog( DLG_DICTGONE );
+ }
+
public void showAboutDialog()
{
m_activity.showDialog( DIALOG_ABOUT );
@@ -283,4 +292,23 @@ public class DlgDelegate {
.create();
}
+ private Dialog createDictGoneDialog()
+ {
+ Utils.logf( "DlgDelegate.createDictGoneDialog() called" );
+ Dialog dialog;
+ dialog = new AlertDialog.Builder( m_activity )
+ .setTitle( R.string.no_dict_title )
+ .setMessage( R.string.no_dict_finish )
+ .setPositiveButton( R.string.button_close_game, null )
+ .create();
+
+ dialog.setOnDismissListener( new DialogInterface.OnDismissListener() {
+ public void onDismiss( DialogInterface di ) {
+ m_activity.finish();
+ }
+ } );
+
+ return dialog;
+ }
+
}
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 0f5e18f6e..b007ee2ae 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameConfig.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameConfig.java
@@ -396,88 +396,91 @@ public class GameConfig extends XWActivity
{
super.onResume();
- int gamePtr = XwJNI.initJNI();
m_giOrig = new CurGameInfo( this );
// 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();
- GameUtils.loadMakeGame( this, gamePtr, m_giOrig, m_gameLock );
- m_gameStarted = XwJNI.model_getNMoves( gamePtr ) > 0
- || XwJNI.comms_isConnected( gamePtr );
-
- if ( m_gameStarted ) {
- if ( null == m_gameLockedCheck ) {
- m_gameLockedCheck =
- (CheckBox)findViewById( R.id.game_locked_check );
- m_gameLockedCheck.setVisibility( View.VISIBLE );
- m_gameLockedCheck.setChecked( true );
- m_gameLockedCheck.setOnClickListener( this );
- }
- handleLockedChange();
- }
-
- m_gi = new CurGameInfo( this, m_giOrig );
-
- m_carOrig = new CommsAddrRec( this );
- if ( XwJNI.game_hasComms( gamePtr ) ) {
- XwJNI.comms_getAddr( gamePtr, m_carOrig );
+ int gamePtr = GameUtils.loadMakeGame( this, m_giOrig, m_gameLock );
+ if ( 0 == gamePtr ) {
+ showDictGoneFinish();
} else {
- String relayName = CommonPrefs.getDefaultRelayHost( this );
- int relayPort = CommonPrefs.getDefaultRelayPort( this );
- XwJNI.comms_getInitialAddr( m_carOrig, relayName, relayPort );
- }
- XwJNI.game_dispose( gamePtr );
+ m_gameStarted = XwJNI.model_getNMoves( gamePtr ) > 0
+ || XwJNI.comms_isConnected( gamePtr );
- m_car = new CommsAddrRec( m_carOrig );
-
- m_notNetworkedGame = DeviceRole.SERVER_STANDALONE == m_gi.serverRole;
- setTitle();
-
- if ( !m_notNetworkedGame ) {
- m_joinPublicCheck =
- (CheckBox)findViewById(R.id.join_public_room_check);
- m_joinPublicCheck.setOnClickListener( this );
- m_joinPublicCheck.setChecked( m_car.ip_relay_seeksPublicRoom );
- Utils.setChecked( this, R.id.advertise_new_room_check,
- m_car.ip_relay_advertiseRoom );
- m_publicRoomsSet =
- (LinearLayout)findViewById(R.id.public_rooms_set );
- m_privateRoomsSet =
- (LinearLayout)findViewById(R.id.private_rooms_set );
-
- Utils.setText( this, R.id.room_edit, m_car.ip_relay_invite );
-
- m_roomChoose = (Spinner)findViewById( R.id.room_spinner );
-
- m_refreshRoomsButton =
- (ImageButton)findViewById( R.id.refresh_button );
- m_refreshRoomsButton.setOnClickListener( this );
-
- adjustConnectStuff();
- }
-
- loadPlayers();
- configLangSpinner();
-
- m_phoniesSpinner.setSelection( m_gi.phoniesAction.ordinal() );
-
- setSmartnessSpinner();
-
- Utils.setChecked( this, R.id.hints_allowed, !m_gi.hintsNotAllowed );
- Utils.setInt( this, R.id.timer_minutes_edit,
- m_gi.gameSeconds/60/m_gi.nPlayers );
-
- CheckBox check = (CheckBox)findViewById( R.id.use_timer );
- CompoundButton.OnCheckedChangeListener lstnr =
- new CompoundButton.OnCheckedChangeListener() {
- public void onCheckedChanged( CompoundButton buttonView,
- boolean checked ) {
- View view = findViewById( R.id.timer_set );
- view.setVisibility( checked ? View.VISIBLE : View.GONE );
+ if ( m_gameStarted ) {
+ if ( null == m_gameLockedCheck ) {
+ m_gameLockedCheck =
+ (CheckBox)findViewById( R.id.game_locked_check );
+ m_gameLockedCheck.setVisibility( View.VISIBLE );
+ m_gameLockedCheck.setChecked( true );
+ m_gameLockedCheck.setOnClickListener( this );
}
- };
- check.setOnCheckedChangeListener( lstnr );
- Utils.setChecked( this, R.id.use_timer, m_gi.timerEnabled );
+ handleLockedChange();
+ }
+
+ m_gi = new CurGameInfo( this, m_giOrig );
+
+ m_carOrig = new CommsAddrRec( this );
+ if ( XwJNI.game_hasComms( gamePtr ) ) {
+ XwJNI.comms_getAddr( gamePtr, m_carOrig );
+ } else {
+ String relayName = CommonPrefs.getDefaultRelayHost( this );
+ int relayPort = CommonPrefs.getDefaultRelayPort( this );
+ XwJNI.comms_getInitialAddr( m_carOrig, relayName, relayPort );
+ }
+ XwJNI.game_dispose( gamePtr );
+
+ m_car = new CommsAddrRec( m_carOrig );
+
+ m_notNetworkedGame = DeviceRole.SERVER_STANDALONE == m_gi.serverRole;
+ setTitle();
+
+ if ( !m_notNetworkedGame ) {
+ m_joinPublicCheck =
+ (CheckBox)findViewById(R.id.join_public_room_check);
+ m_joinPublicCheck.setOnClickListener( this );
+ m_joinPublicCheck.setChecked( m_car.ip_relay_seeksPublicRoom );
+ Utils.setChecked( this, R.id.advertise_new_room_check,
+ m_car.ip_relay_advertiseRoom );
+ m_publicRoomsSet =
+ (LinearLayout)findViewById(R.id.public_rooms_set );
+ m_privateRoomsSet =
+ (LinearLayout)findViewById(R.id.private_rooms_set );
+
+ Utils.setText( this, R.id.room_edit, m_car.ip_relay_invite );
+
+ m_roomChoose = (Spinner)findViewById( R.id.room_spinner );
+
+ m_refreshRoomsButton =
+ (ImageButton)findViewById( R.id.refresh_button );
+ m_refreshRoomsButton.setOnClickListener( this );
+
+ adjustConnectStuff();
+ }
+
+ loadPlayers();
+ configLangSpinner();
+
+ m_phoniesSpinner.setSelection( m_gi.phoniesAction.ordinal() );
+
+ setSmartnessSpinner();
+
+ Utils.setChecked( this, R.id.hints_allowed, !m_gi.hintsNotAllowed );
+ Utils.setInt( this, R.id.timer_minutes_edit,
+ m_gi.gameSeconds/60/m_gi.nPlayers );
+
+ CheckBox check = (CheckBox)findViewById( R.id.use_timer );
+ CompoundButton.OnCheckedChangeListener lstnr =
+ new CompoundButton.OnCheckedChangeListener() {
+ public void onCheckedChanged( CompoundButton buttonView,
+ boolean checked ) {
+ View view = findViewById( R.id.timer_set );
+ view.setVisibility( checked ? View.VISIBLE : View.GONE );
+ }
+ };
+ check.setOnCheckedChangeListener( lstnr );
+ Utils.setChecked( this, R.id.use_timer, m_gi.timerEnabled );
+ }
} // onResume
@Override
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 1d3b584b1..368c06891 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
@@ -158,7 +158,23 @@ public class GameUtils {
public DictPairs( byte[][] bytes, String[] paths ) {
m_bytes = bytes; m_paths = paths;
}
- }
+
+ public boolean anyMissing( final String[] names )
+ {
+ boolean missing = false;
+ for ( int ii = 0; ii < m_paths.length; ++ii ) {
+ if ( names[ii] != null ) {
+ // It's ok for there to be no dict IFF there's no
+ // name. That's a player using the default dict.
+ if ( null == m_paths[ii] && null == m_bytes[ii] ) {
+ missing = true;
+ break;
+ }
+ }
+ }
+ return missing;
+ }
+ } // DictPairs
private static Object s_syncObj = new Object();
@@ -180,15 +196,14 @@ public class GameUtils {
* basis for a new one.
*/
public static GameLock resetGame( Context context, GameLock lockSrc,
- GameLock lockDest )
+ GameLock lockDest )
{
- int gamePtr = XwJNI.initJNI();
CurGameInfo gi = new CurGameInfo( context );
CommsAddrRec addr = null;
// loadMakeGame, if makinga new game, will add comms as long
// as DeviceRole.SERVER_STANDALONE != gi.serverRole
- loadMakeGame( context, gamePtr, gi, lockSrc );
+ int gamePtr = loadMakeGame( context, gi, lockSrc );
String[] dictNames = gi.dictNames();
DictPairs pairs = openDicts( context, dictNames );
@@ -266,9 +281,8 @@ public class GameUtils {
public static GameSummary summarize( Context context, GameLock lock )
{
- int gamePtr = XwJNI.initJNI();
CurGameInfo gi = new CurGameInfo( context );
- loadMakeGame( context, gamePtr, gi, lock );
+ int gamePtr = loadMakeGame( context, gi, lock );
return summarizeAndClose( context, lock, gamePtr, gi );
}
@@ -305,33 +319,41 @@ public class GameUtils {
return result;
}
- public static void loadMakeGame( Context context, int gamePtr,
- CurGameInfo gi, GameLock lock )
+ public static int loadMakeGame( Context context, CurGameInfo gi,
+ GameLock lock )
{
- loadMakeGame( context, gamePtr, gi, null, null, lock );
+ return loadMakeGame( context, gi, null, null, lock );
}
- public static void loadMakeGame( Context context, int gamePtr,
- CurGameInfo gi, UtilCtxt util,
- TransportProcs tp, GameLock lock )
+ public static int loadMakeGame( Context context, CurGameInfo gi,
+ UtilCtxt util, TransportProcs tp,
+ GameLock lock )
{
+ int gamePtr = 0;
+
byte[] stream = savedGame( context, lock );
XwJNI.gi_from_stream( gi, stream );
String[] dictNames = gi.dictNames();
DictPairs pairs = openDicts( context, dictNames );
- String langName = gi.langName();
+ if ( pairs.anyMissing( dictNames ) ) {
+ Utils.logf( "loadMakeGame() failing: dict unavailable" );
+ } else {
+ gamePtr = XwJNI.initJNI();
- boolean madeGame = XwJNI.game_makeFromStream( gamePtr, stream, gi,
- dictNames, pairs.m_bytes,
- pairs.m_paths, langName,
- util, JNIUtilsImpl.get(),
- CommonPrefs.get(context),
- tp );
- if ( !madeGame ) {
- XwJNI.game_makeNewGame( gamePtr, gi, JNIUtilsImpl.get(),
- CommonPrefs.get(context), dictNames,
- pairs.m_bytes, pairs.m_paths, langName );
+ String langName = gi.langName();
+ boolean madeGame = XwJNI.game_makeFromStream( gamePtr, stream, gi,
+ dictNames, pairs.m_bytes,
+ pairs.m_paths, langName,
+ util, JNIUtilsImpl.get(),
+ CommonPrefs.get(context),
+ tp);
+ if ( !madeGame ) {
+ XwJNI.game_makeNewGame( gamePtr, gi, JNIUtilsImpl.get(),
+ CommonPrefs.get(context), dictNames,
+ pairs.m_bytes, pairs.m_paths, langName );
+ }
}
+ return gamePtr;
}
public static long saveGame( Context context, int gamePtr,
@@ -718,7 +740,7 @@ public class GameUtils {
File file = context.getFileStreamPath( name );
if ( !file.exists() ) {
file = getSDPathFor( context, name );
- if ( !file.exists() ) {
+ if ( null != file && !file.exists() ) {
file = null;
}
}
@@ -856,13 +878,12 @@ public class GameUtils {
boolean draw = false;
long rowid = DBUtils.getRowIDFor( context, relayID );
if ( -1 != rowid ) {
- int gamePtr = XwJNI.initJNI();
CurGameInfo gi = new CurGameInfo( context );
FeedUtilsImpl feedImpl = new FeedUtilsImpl( context, rowid );
GameLock lock = new GameLock( rowid, true );
if ( lock.tryLock() ) {
- loadMakeGame( context, gamePtr, gi, feedImpl, sink, lock );
-
+ int gamePtr = loadMakeGame( context, gi, feedImpl, sink, lock );
+
XwJNI.comms_resendAll( gamePtr );
if ( null != msgs ) {
@@ -902,7 +923,7 @@ public class GameUtils {
// 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 )
+ String oldDict, String newDict )
{
GameLock lock = new GameLock( rowid, true ).lock();
byte[] stream = savedGame( context, 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 0b77b8353..e91a13658 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
@@ -97,14 +97,16 @@ public class GamesList extends XWListActivity
}
};
String message;
- String langName = DictLangCache.getLangName( this,
- m_missingDictLang );
+ String langName =
+ DictLangCache.getLangName( this, m_missingDictLang );
+ String gameName = GameUtils.getName( this, m_rowid );
if ( WARN_NODICT == id ) {
- message = String.format( getString(R.string.no_dictf),
- langName );
+ message = String.format( getString( R.string.no_dictf ),
+ gameName, langName );
} else {
message = String.format( getString(R.string.no_dict_substf),
- m_missingDictNames[0], langName );
+ gameName, m_missingDictNames[0],
+ langName );
}
ab = new AlertDialog.Builder( this )
@@ -127,24 +129,26 @@ public class GamesList extends XWListActivity
case SHOW_SUBST:
m_sameLangDicts =
DictLangCache.getHaveLangCounts( this, m_missingDictLang );
- ab = new AlertDialog.Builder( this )
+ lstnr = new DialogInterface.OnClickListener() {
+ public void onClick( DialogInterface dlg,
+ int which ) {
+ int pos = ((AlertDialog)dlg).getListView().
+ getCheckedItemPosition();
+ String dict = m_sameLangDicts[pos];
+ dict = DictLangCache.stripCount( dict );
+ GameUtils.replaceDicts( GamesList.this,
+ m_missingDictRowId,
+ m_missingDictNames[0],
+ dict );
+ }
+ };
+ dialog = new AlertDialog.Builder( this )
.setTitle( R.string.subst_dict_title )
+ .setPositiveButton( R.string.button_substdict, lstnr )
.setNegativeButton( R.string.button_cancel, null )
- .setItems( m_sameLangDicts,
- new DialogInterface.OnClickListener() {
- public void onClick( DialogInterface dlg,
- int which ) {
- String dict = m_sameLangDicts[which];
- dict = DictLangCache.stripCount( dict );
- GameUtils.
- replaceDicts( GamesList.this,
- m_missingDictRowId,
- m_missingDictNames[0],
- dict );
- }
- })
+ .setSingleChoiceItems( m_sameLangDicts, 0, null )
+ .create();
;
- dialog = ab.create();
// Force destruction so onCreateDialog() will get
// called next time and we can insert a different
// list. There seems to be no way to change the list
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 1f0ee8d09..4f23b8ede 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayGameActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayGameActivity.java
@@ -67,10 +67,9 @@ public class RelayGameActivity extends XWActivity
{
super.onStart();
- int gamePtr = XwJNI.initJNI();
m_gi = new CurGameInfo( this );
m_gameLock = new GameUtils.GameLock( m_rowid, true ).lock();
- GameUtils.loadMakeGame( this, gamePtr, m_gi, m_gameLock );
+ int gamePtr = GameUtils.loadMakeGame( this, m_gi, m_gameLock );
m_car = new CommsAddrRec( this );
if ( XwJNI.game_hasComms( gamePtr ) ) {
XwJNI.comms_getAddr( gamePtr, m_car );
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/SDCardWatcher.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/SDCardWatcher.java
new file mode 100644
index 000000000..1492e9731
--- /dev/null
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/SDCardWatcher.java
@@ -0,0 +1,68 @@
+/* -*- 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.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+public class SDCardWatcher {
+ public interface SDCardNotifiee {
+ void cardMounted();
+ }
+
+ private UmountReceiver m_rcvr;
+ private Context m_context;
+ private SDCardNotifiee m_notifiee;
+
+ private class UmountReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive( Context context, Intent intent )
+ {
+ if ( intent.getAction().
+ equals( Intent.ACTION_MEDIA_MOUNTED ) ) {
+ m_notifiee.cardMounted();
+ }
+ }
+ }
+
+ public SDCardWatcher( Context context, SDCardNotifiee notifiee )
+ {
+ m_context = context;
+ m_rcvr = new UmountReceiver();
+ m_notifiee = notifiee;
+
+ IntentFilter filter =
+ new IntentFilter( Intent.ACTION_MEDIA_MOUNTED );
+ // filter.addAction( Intent.ACTION_MEDIA_UNMOUNTED );
+ // filter.addAction( Intent.ACTION_MEDIA_EJECT );
+ filter.addDataScheme( "file" );
+
+ /*Intent intent = */context.getApplicationContext().
+ registerReceiver( m_rcvr, filter );
+ }
+
+ public void close()
+ {
+ m_context.getApplicationContext().unregisterReceiver( m_rcvr );
+ }
+}
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 7bb01a339..d094a9adf 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWActivity.java
@@ -36,6 +36,7 @@ public class XWActivity extends Activity {
private DlgDelegate m_delegate;
+ @Override
protected void onCreate( Bundle savedInstanceState )
{
Utils.logf( "%s.onCreate(this=%H)", getClass().getName(), this );
@@ -84,10 +85,10 @@ public class XWActivity extends Activity {
@Override
protected Dialog onCreateDialog( int id )
{
- Utils.logf( "%s.onCreateDialog() called", getClass().getName() );
- Dialog dialog = m_delegate.onCreateDialog( id );
- if ( null != dialog ) {
- setRemoveOnDismiss( dialog, id );
+ Dialog dialog = super.onCreateDialog( id );
+ if ( null == dialog ) {
+ Utils.logf( "%s.onCreateDialog() called", getClass().getName() );
+ dialog = m_delegate.onCreateDialog( id );
}
return dialog;
}
@@ -100,6 +101,7 @@ public class XWActivity extends Activity {
@Override
protected void onPrepareDialog( int id, Dialog dialog )
{
+ super.onPrepareDialog( id, dialog ); // docs say should call through
m_delegate.onPrepareDialog( id, dialog );
}
@@ -121,6 +123,11 @@ public class XWActivity extends Activity {
m_delegate.showOKOnlyDialog( msgID );
}
+ protected void showDictGoneFinish()
+ {
+ m_delegate.showDictGoneFinish();
+ }
+
protected void showConfirmThen( int msgID,
DialogInterface.OnClickListener action )
{
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 77fe99799..bb1206eff 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListActivity.java
@@ -106,6 +106,7 @@ public class XWListActivity extends ListActivity {
@Override
protected void onPrepareDialog( int id, Dialog dialog )
{
+ super.onPrepareDialog( id, dialog );
m_delegate.onPrepareDialog( id, dialog );
}
diff --git a/xwords4/common/movestak.c b/xwords4/common/movestak.c
index 4bb44740b..ac2295fa2 100644
--- a/xwords4/common/movestak.c
+++ b/xwords4/common/movestak.c
@@ -61,6 +61,7 @@ void
stack_setBitsPerTile( StackCtxt* stack, XP_U16 bitsPerTile )
{
XP_ASSERT( !!stack );
+ XP_ASSERT( bitsPerTile == 5 || bitsPerTile == 6 );
stack->bitsPerTile = bitsPerTile;
}
diff --git a/xwords4/linux/scripts/discon_ok2.sh b/xwords4/linux/scripts/discon_ok2.sh
index 9508f9243..36bbca4a4 100755
--- a/xwords4/linux/scripts/discon_ok2.sh
+++ b/xwords4/linux/scripts/discon_ok2.sh
@@ -225,11 +225,17 @@ close_device() {
unset ROOMS[$ID]
}
+OBITS=""
+
kill_from_log() {
LOG=$1
RELAYID=$(./scripts/relayID.sh --long $LOG)
if [ -n "$RELAYID" ]; then
- ../relay/rq -a $HOST -d $RELAYID 2>/dev/null || true
+ OBITS="$OBITS -d $RELAYID"
+ if [ 0 -eq $(($RANDOM%2)) ]; then
+ ../relay/rq -a $HOST $OBITS 2>/dev/null || true
+ OBITS=""
+ fi
return 0 # success
fi
echo "unable to send kill command for $LOG"
@@ -281,10 +287,15 @@ check_game() {
close_device $ID $DONEDIR "game over"
done
date
+ # XWRELAY_ERROR_DELETED may be old
elif grep -q 'relay_error_curses(XWRELAY_ERROR_DELETED)' $LOG; then
echo "deleting $LOG $(connName $LOG) b/c another resigned"
kill_from_log $LOG || true
close_device $KEY $DEADDIR "other resigned"
+ elif grep -q 'relay_error_curses(XWRELAY_ERROR_DEADGAME)' $LOG; then
+ echo "deleting $LOG $(connName $LOG) b/c another resigned"
+ kill_from_log $LOG || true
+ close_device $KEY $DEADDIR "other resigned"
else
maybe_resign $KEY
fi
@@ -334,6 +345,8 @@ run_cmds() {
fi
done
+ [ -n "$OBITS" ] && ../relay/rq -a $HOST $OBITS 2>/dev/null || true
+
# kill any remaining games
if [ $COUNT -gt 0 ]; then
mkdir -p ${LOGDIR}/not_done