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 7731a06b9..287f402a4 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java @@ -23,10 +23,14 @@ import android.app.AlertDialog; import android.content.DialogInterface; import org.eehouse.android.xw4.jni.*; +import org.eehouse.android.xw4.jni.JNIThread.*; + public class BoardActivity extends Activity implements XW_UtilCtxt, Runnable { private static final int PICK_TILE_REQUEST = 1; + private static final int QUERY_REQUEST = 2; + private static final int INFORM_REQUEST = 3; private BoardView m_view; private int m_jniGamePtr; @@ -37,7 +41,6 @@ public class BoardActivity extends Activity implements XW_UtilCtxt, Runnable { private String m_path; private final int DLG_OKONLY = 1; - private final int DLG_QUERY = 2; private String m_dlgBytes = null; private int m_dlgTitle; private boolean m_dlgResult; @@ -48,6 +51,7 @@ public class BoardActivity extends Activity implements XW_UtilCtxt, Runnable { private Intent m_resultIntent = null; private JNIThread m_jniThread; + private JNIThread m_jniThread_pending; public class TimerRunnable implements Runnable { private int m_gamePtr; @@ -61,8 +65,10 @@ public class BoardActivity extends Activity implements XW_UtilCtxt, Runnable { } public void run() { m_timers[m_why] = null; - m_jniThread.handle( JNIThread.JNICmd.CMD_TIMER_FIRED, - new Object[] { m_why, m_when, m_handle } ); + if ( null != m_jniThread ) { + m_jniThread.handle( JNICmd.CMD_TIMER_FIRED, + m_why, m_when, m_handle ); + } } } @@ -152,17 +158,26 @@ public class BoardActivity extends Activity implements XW_UtilCtxt, Runnable { m_prefs, null, dictBytes ); } - m_jniThread = new JNIThread( m_jniGamePtr, - new Handler() { - public void handleMessage( Message msg ) { - Utils.logf( "handleMessage called" ); - m_view.invalidate(); - } - } ); - m_jniThread.start(); - m_view.startHandling( m_jniThread, m_jniGamePtr, m_gi ); - - m_jniThread.handle( JNIThread.JNICmd.CMD_DO ); + m_jniThread_pending = new + JNIThread( m_jniGamePtr, + new Handler() { + public void handleMessage( Message msg ) { + Utils.logf( "handleMessage() called" ); + switch( msg.what ) { + case JNIThread.RUNNING: + m_jniThread = m_jniThread_pending; + m_view.startHandling( m_jniThread, + m_jniGamePtr, + m_gi ); + m_jniThread.handle( JNICmd.CMD_DO ); + break; + case JNIThread.DRAW: + m_view.invalidate(); + break; + } + } + } ); + m_jniThread_pending.start(); Utils.logf( "BoardActivity::onCreate() done" ); } // onCreate @@ -175,6 +190,7 @@ public class BoardActivity extends Activity implements XW_UtilCtxt, Runnable { protected void onDestroy() { + // what if m_jniThread is null? m_jniThread.waitToStop(); saveGame(); XwJNI.game_dispose( m_jniGamePtr ); @@ -187,9 +203,9 @@ public class BoardActivity extends Activity implements XW_UtilCtxt, Runnable { Intent result ) { Utils.logf( "onActivityResult called" ); - this.m_resultCode = resultCode; - this.m_resultIntent = result; - this.m_forResultWait.release(); + m_resultCode = resultCode; + m_resultIntent = result; + m_forResultWait.release(); } public boolean onCreateOptionsMenu(Menu menu) { @@ -270,7 +286,9 @@ public class BoardActivity extends Activity implements XW_UtilCtxt, Runnable { } if ( handled && cmd != JNIThread.JNICmd.CMD_NONE ) { - m_jniThread.handle( cmd ); + if ( null != m_jniThread ) { + m_jniThread.handle( cmd ); + } } return handled; @@ -415,7 +433,7 @@ public class BoardActivity extends Activity implements XW_UtilCtxt, Runnable { public boolean engineProgressCallback() { - return !m_jniThread.busy(); + return null != m_jniThread && !m_jniThread.busy(); } public String getUserString( int stringCode ) @@ -509,18 +527,107 @@ public class BoardActivity extends Activity implements XW_UtilCtxt, Runnable { public boolean userQuery( int id, String query ) { + String actString = XWConstants.ACTION_QUERY; + switch( id ) { + case XW_UtilCtxt.QUERY_ROBOT_MOVE: + case XW_UtilCtxt.QUERY_ROBOT_TRADE: + actString = XWConstants.ACTION_INFORM; + break; case XW_UtilCtxt.QUERY_COMMIT_TRADE: query = getString( R.string.query_trade ); break; case XW_UtilCtxt.QUERY_COMMIT_TURN: - case XW_UtilCtxt.QUERY_ROBOT_MOVE: - case XW_UtilCtxt.QUERY_ROBOT_TRADE: break; } // Need to figure out how this thing can block. - return true; + + Intent intent = new Intent( BoardActivity.this, BlockingActivity.class ); + intent.setAction( actString ); + + Bundle bundle = new Bundle(); + bundle.putString( XWConstants.QUERY_QUERY, query ); + intent.putExtra( XWConstants.QUERY_QUERY, bundle ); + + boolean userConfirmed = false; + try { + startActivityForResult( intent, QUERY_REQUEST ); + m_forResultWait.acquire(); + Utils.logf( "userQuery back from acquire" ); + userConfirmed = m_resultCode != 0; + } catch ( Exception ee ) { + Utils.logf( "userPickTile got: " + ee.toString() ); + } + + return userConfirmed; } + public void userError( int code ) + { + int resid = 0; + switch( code ) { + case ERR_TILES_NOT_IN_LINE: + resid = R.string.str_tiles_not_in_line; + break; + case ERR_NO_EMPTIES_IN_TURN: + resid = R.string.str_no_empties_in_turn; + break; + case ERR_TWO_TILES_FIRST_MOVE: + resid = R.string.str_two_tiles_first_move; + break; + case ERR_TILES_MUST_CONTACT: + resid = R.string.str_tiles_must_contact; + break; + case ERR_NOT_YOUR_TURN: + resid = R.string.str_not_your_turn; + break; + case ERR_NO_PEEK_ROBOT_TILES: + resid = R.string.str_no_peek_robot_tiles; + break; + case ERR_CANT_TRADE_MID_MOVE: + resid = R.string.str_cant_trade_mid_move; + break; + case ERR_TOO_FEW_TILES_LEFT_TO_TRADE: + resid = R.string.str_too_few_tiles_left_to_trade; + break; + case ERR_CANT_UNDO_TILEASSIGN: + resid = R.string.str_cant_undo_tileassign; + break; + case ERR_CANT_HINT_WHILE_DISABLED: + resid = R.string.str_cant_hint_while_disabled; + break; + case ERR_NO_PEEK_REMOTE_TILES: + resid = R.string.str_no_peek_remote_tiles; + break; + case ERR_REG_UNEXPECTED_USER: + resid = R.string.str_reg_unexpected_user; + break; + case ERR_SERVER_DICT_WINS: + resid = R.string.str_server_dict_wins; + break; + case ERR_REG_SERVER_SANS_REMOTE: + resid = R.string.str_reg_server_sans_remote; + break; + } + + if ( resid != 0 ) { + String txt = getString( resid ); + + Intent intent = new Intent( BoardActivity.this, BlockingActivity.class ); + intent.setAction( XWConstants.ACTION_INFORM ); + + Bundle bundle = new Bundle(); + bundle.putString( XWConstants.QUERY_QUERY, txt ); + intent.putExtra( XWConstants.QUERY_QUERY, bundle ); + + try { + startActivityForResult( intent, INFORM_REQUEST ); + m_forResultWait.acquire(); + } catch ( Exception ee ) { + Utils.logf( "userPickTile got: " + ee.toString() ); + } + } + } // userError + } // class BoardActivity diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWConstants.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWConstants.java index 7e5b98da3..cbef22a99 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWConstants.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWConstants.java @@ -10,8 +10,8 @@ public interface XWConstants { public static final String PICK_TILE_TILES = "org.eehouse.android.xw4.PICK_TILE_TILES"; - public static final String PICK_TILE_TILE - = "org.eehouse.android.xw4.PICK_TILE_TILE"; + // public static final String PICK_TILE_TILE + // = "org.eehouse.android.xw4.PICK_TILE_TILE"; // These are duplicated in AndroidManifest.xml. If change here // must change there too to keep in sync. @@ -19,4 +19,10 @@ public interface XWConstants { = "org.eehouse.android.xw4.action.PICK_TILE"; public final String CATEGORY_PICK_TILE = "org.eehouse.android.xw4.category.PICK_TILE"; + + public final String ACTION_QUERY = "org.eehouse.android.xw4.action.QUERY"; + public final String ACTION_INFORM= "org.eehouse.android.xw4.action.INFORM"; + public static final String QUERY_QUERY + = "org.eehouse.android.xw4.QUERY_QUERY"; + } diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CommonPrefs.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CommonPrefs.java index 9272478fd..bad8270d1 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CommonPrefs.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CommonPrefs.java @@ -8,8 +8,8 @@ public class CommonPrefs { public CommonPrefs() { showBoardArrow = true; - showRobotScores = false; + showRobotScores = true; hideTileValues = false; - skipCommitConfirm = true; + skipCommitConfirm = false; } } diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java index 8f2d5b5d2..f4e4c33f0 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java @@ -9,6 +9,7 @@ import java.lang.InterruptedException; import java.util.concurrent.LinkedBlockingQueue; import android.os.Handler; import android.os.Message; +import android.os.Looper; public class JNIThread extends Thread { @@ -29,33 +30,26 @@ public class JNIThread extends Thread { CMD_HINT, CMD_NEXT_HINT, CMD_VALUES, + + CMD_STOP, }; - private boolean m_stopped = false; + public static final int RUNNING = 1; + public static final int DRAW = 2; + private int m_jniGamePtr; - private Handler m_handler; - LinkedBlockingQueue m_queue; - - private class QueueElem { - protected QueueElem( JNICmd cmd, Object[] args ) - { - m_cmd = cmd; m_args = args; - } - JNICmd m_cmd; - Object[] m_args; - } - + private Handler m_parentHandler; + private Handler m_loopHandler; + private boolean[] m_barr = new boolean[1]; // scratch boolean + public JNIThread( int gamePtr, Handler handler ) { Utils.logf( "in JNIThread()" ); m_jniGamePtr = gamePtr; - m_handler = handler; - - m_queue = new LinkedBlockingQueue(); + m_parentHandler = handler; } public void waitToStop() { - m_stopped = true; - handle( JNICmd.CMD_NONE ); // tickle it + handle( JNICmd.CMD_STOP ); try { join(); } catch ( java.lang.InterruptedException ie ) { @@ -64,9 +58,10 @@ public class JNIThread extends Thread { } public boolean busy() - { // synchronize this!!! - int siz = m_queue.size(); - return siz > 0; + { + // HTF to I tell if my queue has anything in it. Do I have to + // keep a counter? Which means synchronizing... + return false; } private boolean toggleTray() { @@ -82,103 +77,111 @@ public class JNIThread extends Thread { public void run() { - boolean[] barr = new boolean[1]; // scratch boolean - while ( !m_stopped ) { - QueueElem elem; - Object[] args; - try { - elem = m_queue.take(); - } catch ( InterruptedException ie ) { - Utils.logf( "interrupted; killing thread" ); - break; - } - boolean draw = false; - args = elem.m_args; - switch( elem.m_cmd ) { + Looper.prepare(); + + m_loopHandler = new Handler() { + public void handleMessage( Message msg ) { + boolean draw = false; + Object[] args = (Object[])msg.obj; + switch( JNICmd.values()[msg.what] ) { - case CMD_DRAW: - draw = true; - break; - case CMD_DO: - draw = XwJNI.server_do( m_jniGamePtr ); - break; + case CMD_DRAW: + draw = true; + break; + case CMD_DO: + draw = XwJNI.server_do( m_jniGamePtr ); + break; - case CMD_PEN_DOWN: - draw = XwJNI.board_handlePenDown( m_jniGamePtr, - ((Integer)args[0]).intValue(), - ((Integer)args[1]).intValue(), - barr ); - break; - case CMD_PEN_MOVE: - draw = XwJNI.board_handlePenMove( m_jniGamePtr, - ((Integer)args[0]).intValue(), - ((Integer)args[1]).intValue() ); - break; - case CMD_PEN_UP: - draw = XwJNI.board_handlePenUp( m_jniGamePtr, - ((Integer)args[0]).intValue(), - ((Integer)args[1]).intValue() ); - break; + case CMD_PEN_DOWN: + draw = XwJNI.board_handlePenDown( m_jniGamePtr, + ((Integer)args[0]).intValue(), + ((Integer)args[1]).intValue(), + m_barr ); + break; + case CMD_PEN_MOVE: + draw = XwJNI.board_handlePenMove( m_jniGamePtr, + ((Integer)args[0]).intValue(), + ((Integer)args[1]).intValue() ); + break; + case CMD_PEN_UP: + draw = XwJNI.board_handlePenUp( m_jniGamePtr, + ((Integer)args[0]).intValue(), + ((Integer)args[1]).intValue() ); + break; - case CMD_COMMIT: - draw = XwJNI.board_commitTurn( m_jniGamePtr ); - break; + case CMD_COMMIT: + draw = XwJNI.board_commitTurn( m_jniGamePtr ); + break; - case CMD_JUGGLE: - draw = XwJNI.board_juggleTray( m_jniGamePtr ); - break; - case CMD_FLIP: - draw = XwJNI.board_flip( m_jniGamePtr ); - break; - case CMD_TOGGLE_TRAY: - draw = toggleTray(); - break; - case CMD_TOGGLE_TRADE: - draw = XwJNI.board_beginTrade( m_jniGamePtr ); - break; - case CMD_UNDO_CUR: - draw = XwJNI.board_replaceTiles( m_jniGamePtr ); - break; - case CMD_UNDO_LAST: - XwJNI.server_handleUndo( m_jniGamePtr ); - draw = true; - break; + case CMD_JUGGLE: + draw = XwJNI.board_juggleTray( m_jniGamePtr ); + break; + case CMD_FLIP: + draw = XwJNI.board_flip( m_jniGamePtr ); + break; + case CMD_TOGGLE_TRAY: + draw = toggleTray(); + break; + case CMD_TOGGLE_TRADE: + draw = XwJNI.board_beginTrade( m_jniGamePtr ); + break; + case CMD_UNDO_CUR: + draw = XwJNI.board_replaceTiles( m_jniGamePtr ); + break; + case CMD_UNDO_LAST: + XwJNI.server_handleUndo( m_jniGamePtr ); + draw = true; + break; - case CMD_HINT: - XwJNI.board_resetEngine( m_jniGamePtr ); - // fallthru - case CMD_NEXT_HINT: - draw = XwJNI.board_requestHint( m_jniGamePtr, false, barr ); - if ( barr[0] ) { - handle( JNICmd.CMD_NEXT_HINT ); + case CMD_HINT: + XwJNI.board_resetEngine( m_jniGamePtr ); + // fallthru + case CMD_NEXT_HINT: + draw = XwJNI.board_requestHint( m_jniGamePtr, false, m_barr ); + if ( m_barr[0] ) { + handle( JNICmd.CMD_NEXT_HINT ); + } + break; + + case CMD_VALUES: + draw = XwJNI.board_toggle_showValues( m_jniGamePtr ); + break; + + case CMD_TIMER_FIRED: + draw = XwJNI.timerFired( m_jniGamePtr, + ((Integer)args[0]).intValue(), + ((Integer)args[1]).intValue(), + ((Integer)args[2]).intValue() ); + break; + + case CMD_STOP: + Looper.myLooper().quit(); + break; + } + + if ( draw ) { + if ( !XwJNI.board_draw( m_jniGamePtr ) ) { + Utils.logf( "draw not complete" ); + } + Message.obtain( m_parentHandler, DRAW ).sendToTarget(); + } } - break; + }; - case CMD_VALUES: - draw = XwJNI.board_toggle_showValues( m_jniGamePtr ); - break; + // Safe to use us now + Message.obtain( m_parentHandler, RUNNING ).sendToTarget(); + + Looper.loop(); - case CMD_TIMER_FIRED: - draw = XwJNI.timerFired( m_jniGamePtr, - ((Integer)args[0]).intValue(), - ((Integer)args[1]).intValue(), - ((Integer)args[2]).intValue() ); - break; - } - - if ( draw ) { - if ( !XwJNI.board_draw( m_jniGamePtr ) ) { - Utils.logf( "draw not complete" ); - } - m_handler.post(null); - } - } Utils.logf( "run exiting" ); } // run + + /** Post a cmd to be handled by the JNI thread + */ public void handle( JNICmd cmd, Object... args ) { - QueueElem elem = new QueueElem( cmd, args ); - m_queue.add( elem ); + Message message = Message.obtain( m_loopHandler, cmd.ordinal(), args ); + message.sendToTarget(); } }