when sd card is umounted, android sends a message to apps. I can't

figure out how to get that so I ignore it and am killed then
relaunched if I have a dict file open on the SD.  On relauch, don't
crash.  Instead, check if any dicts used by the game is unreachable
and put up an alert with only one choice: Close game.  Thought about
using the missing-dicts stuff from GamesList, but this is a special
case that should be seen only when user umounts while a BoardActivity
instance is frontmost.
This commit is contained in:
Andy2 2011-08-18 07:54:00 -07:00
parent 7a1346e530
commit fd4e627628
3 changed files with 125 additions and 80 deletions

View file

@ -389,13 +389,18 @@
<string name="subst_dict_title">Substitute dictionary (wordcount)</string>
<string name="button_substdict">Substitute</string>
<string name="button_close_game">Close game</string>
<string name="no_dict_finish">A dictionary this game is using has
disappeared. (Usually this means it\'s on an external card that
is no longer available.)</string>
<string name="no_dictf">Unable to open game \"%1$s\" because no
%2$s dictionary found. (It may have been deleted, or stored on
an an SD card that\'s been unmounted.)</string>
an external card that is no longer available.)</string>
<string name="no_dict_substf">Unable to open game \"%1$s\" because
dictionary %2$s not found. (It may have been deleted, or stored
on an an SD card that\'s been unmounted.) You can download a
replacement or substitute another %3$s dictionary.</string>
on an external card that is no longer available.) You can
download a replacement or substitute another %3$s
dictionary.</string>
<string name="msg_ask_password">Password for \"%s\":</string>

View file

@ -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;
@ -68,6 +69,7 @@ public class BoardActivity extends XWActivity
private static final int QUERY_ENDGAME = DLG_OKONLY + 7;
private static final int DLG_DELETED = DLG_OKONLY + 8;
private static final int DLG_INVITE = DLG_OKONLY + 9;
private static final int DLG_NODICT = DLG_OKONLY + 10;
private static final int CHAT_REQUEST = 1;
private static final int SCREEN_ON_TIME = 10 * 60 * 1000; // 10 mins
@ -80,7 +82,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;
@ -286,6 +288,21 @@ public class BoardActivity extends XWActivity
.create();
}
break;
case DLG_NODICT:
dialog = new AlertDialog.Builder( this )
.setTitle( R.string.no_dict_title )
.setMessage( R.string.no_dict_finish )
.setPositiveButton( R.string.button_close_game, null )
.create();
OnDismissListener dlstnr;
dlstnr = new OnDismissListener() {
public void onDismiss( DialogInterface di ) {
// removeDialog( DLG_NODICT );
finish();
}
};
dialog.setOnDismissListener( dlstnr );
break;
default:
// just drop it; super.onCreateDialog likely failed
break;
@ -1044,89 +1061,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 ) ) {
showDialog( DLG_NODICT );
} 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 +1233,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 );

View file

@ -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,7 +196,7 @@ 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 );
@ -897,7 +913,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 );