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