move BT device listing into its own Activity. Call it from

NewGameActivity and from BoardActivity when the new notifyMissing
method gets called.  Works as before called from NewGameActivity but
BoardActivity crashes on iterating over list of devices returned.
This commit is contained in:
Eric House 2012-02-09 05:21:23 -08:00
parent 0755a9e781
commit 74aeeca8e0
9 changed files with 356 additions and 133 deletions

View file

@ -63,6 +63,9 @@
<activity android:name="NewGameActivity"
android:theme="@android:style/Theme.NoTitleBar"
/>
<activity android:name="BTInviteActivity"
android:theme="@android:style/Theme.NoTitleBar"
/>
<activity android:name="GameConfig"
android:screenOrientation="sensor"

View file

@ -429,16 +429,6 @@ and_util_remSelected(XW_UtilCtxt* uc)
UTIL_CBK_TAIL();
}
static void
and_util_setIsServer(XW_UtilCtxt* uc, XP_Bool isServer )
{
/* Change both the C and Java structs, which need to stay in sync */
uc->gameInfo->serverRole = isServer? SERVER_ISSERVER : SERVER_ISCLIENT;
UTIL_CBK_HEADER("setIsServer", "(Z)V" );
(*env)->CallVoidMethod( env, util->jutil, mid, isServer );
UTIL_CBK_TAIL();
}
#ifndef XWFEATURE_MINIWIN
static void
and_util_bonusSquareHeld( XW_UtilCtxt* uc, XWBonusType bonus )
@ -473,6 +463,22 @@ and_util_cellSquareHeld( XW_UtilCtxt* uc, XWStreamCtxt* words )
#endif
#ifndef XWFEATURE_STANDALONE_ONLY
static void
and_util_informMissing(XW_UtilCtxt* uc, XP_Bool isServer,
CommsConnType connType, XP_U16 nMissing )
{
UTIL_CBK_HEADER( "informMissing",
"(ZLorg/eehouse/android/xw4/jni/"
"CommsAddrRec$CommsConnType;I)V" );
jobject jtyp = intToJEnum( env, connType,
"org/eehouse/android/xw4/jni/"
"CommsAddrRec$CommsConnType" );
(*env)->CallVoidMethod( env, util->jutil, mid, isServer, jtyp, nMissing );
(*env)->DeleteLocalRef( env, jtyp );
UTIL_CBK_TAIL();
}
static void
and_util_addrChange( XW_UtilCtxt* uc, const CommsAddrRec* oldAddr,
const CommsAddrRec* newAddr )
@ -480,6 +486,15 @@ and_util_addrChange( XW_UtilCtxt* uc, const CommsAddrRec* oldAddr,
LOG_FUNC();
}
static void
and_util_setIsServer(XW_UtilCtxt* uc, XP_Bool isServer )
{
/* Change both the C and Java structs, which need to stay in sync */
uc->gameInfo->serverRole = isServer? SERVER_ISSERVER : SERVER_ISCLIENT;
UTIL_CBK_HEADER("setIsServer", "(Z)V" );
(*env)->CallVoidMethod( env, util->jutil, mid, isServer );
UTIL_CBK_TAIL();
}
#endif
#ifdef XWFEATURE_SEARCHLIMIT
@ -557,7 +572,6 @@ makeUtil( MPFORMAL JNIEnv** envp, jobject jutil, CurGameInfo* gi,
SET_PROC(warnIllegalWord);
SET_PROC(showChat);
SET_PROC(remSelected);
SET_PROC(setIsServer);
#ifndef XWFEATURE_MINIWIN
SET_PROC(bonusSquareHeld);
@ -569,7 +583,9 @@ makeUtil( MPFORMAL JNIEnv** envp, jobject jutil, CurGameInfo* gi,
#endif
#ifndef XWFEATURE_STANDALONE_ONLY
SET_PROC(informMissing);
SET_PROC(addrChange);
SET_PROC(setIsServer);
#endif
#ifdef XWFEATURE_SEARCHLIMIT
SET_PROC(getTraySearchLimits);

View file

@ -0,0 +1,207 @@
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2011 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.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
// import android.content.res.Resources;
// import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
// import android.view.Window;
import android.widget.AdapterView;
// import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ListView;
import android.os.Handler;
// import android.widget.TextView;
// import android.app.AlertDialog;
// import java.util.ArrayList;
// import android.util.AttributeSet;
import junit.framework.Assert;
public class BTInviteActivity extends XWListActivity
implements View.OnClickListener,
CompoundButton.OnCheckedChangeListener {
public static final String DEVS = "DEVS";
public static final String INTENT_KEY_NMISSING = "NMISSING";
private Button m_okButton;
private Button m_rescanButton;
private Button m_reconfigureButton;
private String[] m_btDevNames;
private int m_nMissing;
private Handler m_handler;
private int m_checkCount = 0;
@Override
protected void onCreate( Bundle savedInstanceState )
{
super.onCreate( savedInstanceState );
Intent intent = getIntent();
m_nMissing = intent.getIntExtra( INTENT_KEY_NMISSING, -1 );
setContentView( R.layout.btinviter );
// getListView().setOnItemClickListener( this );
m_okButton = (Button)findViewById( R.id.button_ok );
m_okButton.setOnClickListener( this );
m_rescanButton = (Button)findViewById( R.id.button_rescan );
m_rescanButton.setOnClickListener( this );
m_reconfigureButton = (Button)findViewById( R.id.button_reconfigure );
m_reconfigureButton.setOnClickListener( this );
m_handler = new Handler();
m_checkCount = 0;
tryEnable();
}
@Override
protected void onResume()
{
super.onResume();
if ( null == m_btDevNames ) {
rescan();
}
}
public void onClick( View view )
{
DbgUtils.logf( "onClick" );
if ( m_okButton == view ) {
DbgUtils.logf( "OK BUTTON" );
Intent intent = new Intent();
String[] devs = listSelected();
intent.putExtra( DEVS, devs );
setResult( Activity.RESULT_OK, intent );
finish();
} else if ( m_rescanButton == view ) {
rescan();
} else if ( m_reconfigureButton == view ) {
}
}
// /* AdapterView.OnItemClickListener */
// public void onItemClick( AdapterView<?> parent, View view,
// int position, long id )
// {
// DbgUtils.logf( "BTInviteActivity.onItemClick(position=%d)", position );
// }
public void onCheckedChanged( CompoundButton buttonView,
boolean isChecked )
{
DbgUtils.logf( "BTInviteActivity.onCheckedChanged( isChecked=%b )",
isChecked );
if ( isChecked ) {
++m_checkCount;
} else {
--m_checkCount;
}
tryEnable();
}
// BTService.BTEventListener interface
@Override
public void eventOccurred( BTService.BTEvent event, final Object ... args )
{
switch( event ) {
case SCAN_DONE:
m_handler.post( new Runnable() {
public void run() {
synchronized( BTInviteActivity.this ) {
stopProgress();
if ( 0 < args.length ) {
m_btDevNames = (String[])(args[0]);
}
setListAdapter( new BTDevsAdapter( m_btDevNames ) );
m_checkCount = 0;
tryEnable();
}
}
} );
break;
default:
super.eventOccurred( event, args );
}
}
private void rescan()
{
startProgress( R.string.scan_progress );
BTService.rescan( this );
}
private String[] listSelected()
{
ListView list = (ListView)findViewById( android.R.id.list );
String[] result = new String[m_checkCount];
int count = list.getChildCount();
int index = 0;
for ( int ii = 0; ii < count; ++ii ) {
CheckBox box = (CheckBox)list.getChildAt( ii );
if ( box.isChecked() ) {
result[index++] = box.getText().toString();
}
}
return result;
}
private void tryEnable()
{
m_okButton.setEnabled( m_checkCount == m_nMissing );
}
private class BTDevsAdapter extends XWListAdapter {
private String[] m_devs;
public BTDevsAdapter( String[] devs )
{
super( devs.length );
m_devs = devs;
}
public Object getItem( int position) { return m_devs[position]; }
public View getView( final int position, View convertView,
ViewGroup parent ) {
CheckBox box = (CheckBox)
Utils.inflate( BTInviteActivity.this, R.layout.btinviter_item );
box.setText( m_devs[position] );
box.setOnCheckedChangeListener( BTInviteActivity.this );
return box;
}
}
}

View file

@ -75,6 +75,8 @@ public class BoardActivity extends XWActivity
private static final int PICK_TILE_REQUESTTRAY_BLK = DLG_OKONLY + 12;
private static final int CHAT_REQUEST = 1;
private static final int BT_INVITE_RESULT = 2;
private static final int SCREEN_ON_TIME = 10 * 60 * 1000; // 10 mins
private static final int UNDO_LAST_ACTION = 1;
@ -93,6 +95,7 @@ public class BoardActivity extends XWActivity
private static final int LOOKUP_ACTION = 14;
private static final int BUTTON_BROWSE_ACTION = 15;
private static final int VALUES_ACTION = 16;
private static final int BT_PICK_ACTION = 17;
private static final String DLG_TITLE = "DLG_TITLE";
private static final String DLG_TITLESTR = "DLG_TITLESTR";
@ -131,6 +134,8 @@ public class BoardActivity extends XWActivity
private boolean m_volKeysZoom;
private boolean m_inTrade; // save this in bundle?
private BoardUtilCtxt m_utils;
private int m_nMissingPlayers = -1;
private int m_invitesPending;
// call startActivityForResult synchronously
private Semaphore m_forResultWait = new Semaphore(0);
@ -510,12 +515,24 @@ public class BoardActivity extends XWActivity
protected void onActivityResult( int requestCode, int resultCode, Intent data )
{
if ( Activity.RESULT_CANCELED != resultCode ) {
if ( CHAT_REQUEST == requestCode ) {
switch ( requestCode ) {
case CHAT_REQUEST:
String msg = data.getStringExtra( INTENT_KEY_CHAT );
if ( null != msg && msg.length() > 0 ) {
m_pendingChats.add( msg );
trySendChats();
}
break;
case BT_INVITE_RESULT:
m_invitesPending = 0;
String[] devs = data.getStringArrayExtra( BTInviteActivity.DEVS );
for ( String dev : devs ) {
BTService.inviteRemote( this, dev, m_gi.gameID, m_gi.dictLang,
m_gi.nPlayers, 1 );
++m_invitesPending;
}
startProgress( R.string.invite_progress );
break;
}
}
}
@ -720,6 +737,10 @@ public class BoardActivity extends XWActivity
case SYNC_ACTION:
doSyncMenuitem();
break;
case BT_PICK_ACTION:
GameUtils.launchBTInviter( this, m_nMissingPlayers,
BT_INVITE_RESULT );
break;
case COMMIT_ACTION:
cmd = JNIThread.JNICmd.CMD_COMMIT;
break;
@ -807,6 +828,18 @@ public class BoardActivity extends XWActivity
}
} );
break;
case NEWGAME_FAILURE:
DbgUtils.logf( "failed to create game" );
case NEWGAME_SUCCESS:
if ( 0 == --m_invitesPending ) {
m_handler.post( new Runnable() {
public void run() {
stopProgress();
}
} );
}
break;
default:
super.eventOccurred( event, args );
break;
@ -1296,6 +1329,26 @@ public class BoardActivity extends XWActivity
}
} // userError
@Override
public void informMissing( boolean isServer,
CommsAddrRec.CommsConnType connType,
final int nMissingPlayers )
{
if ( isServer &&
CommsAddrRec.CommsConnType.COMMS_CONN_BT == connType ) {
post( new Runnable() {
public void run() {
DbgUtils.showf( BoardActivity.this,
"%d players missing",
nMissingPlayers );
m_nMissingPlayers = nMissingPlayers;
showConfirmThen( R.string.bt_devs_missing,
BT_PICK_ACTION );
}
} );
}
}
@Override
public void informMove( String expl, String words )
{

View file

@ -454,6 +454,14 @@ public class GameUtils {
null, gameID, isHost );
}
public static void launchBTInviter( Activity activity, int nMissing,
int replyCode )
{
Intent intent = new Intent( activity, BTInviteActivity.class );
intent.putExtra( BTInviteActivity.INTENT_KEY_NMISSING, nMissing );
activity.startActivityForResult( intent, replyCode );
}
public static void launchInviteActivity( Context context,
boolean choseEmail,
String room, String inviteID,

View file

@ -48,13 +48,12 @@ public class NewGameActivity extends XWActivity {
private static final int NEW_GAME_ACTION = 1;
private static final String SAVE_DEVNAMES = "DEVNAMES";
private static final int PICK_BTDEV_DLG = DlgDelegate.DIALOG_LAST + 1;
private static final int CONFIG_BT = 1;
private static final int CONFIG_FOR_BT = 1;
private static final int INVITE_FOR_BT = 2;
private boolean m_showsOn;
private Handler m_handler = null;
private int m_chosen;
private String[] m_btDevNames;
private int m_lang = 0;
private long m_btRowID = -1;
@ -62,7 +61,6 @@ public class NewGameActivity extends XWActivity {
protected void onCreate( Bundle savedInstanceState )
{
super.onCreate( savedInstanceState );
getBundledData( savedInstanceState );
m_handler = new Handler();
@ -109,81 +107,6 @@ public class NewGameActivity extends XWActivity {
checkEnableBT( true );
}
@Override
protected Dialog onCreateDialog( final int id )
{
Dialog dialog = super.onCreateDialog( id );
if ( null == dialog ) {
AlertDialog.Builder ab;
OnClickListener lstnr;
switch( id ) {
case PICK_BTDEV_DLG:
OnClickListener scanLstnr =
new OnClickListener() {
public void onClick( DialogInterface dlg,
int whichButton ) {
startProgress( R.string.scan_progress );
BTService.rescan( NewGameActivity.this );
}
};
OnClickListener okLstnr =
new OnClickListener() {
public void onClick( DialogInterface dlg,
int whichButton ) {
if ( 0 <= m_chosen ) {
if ( m_chosen < m_btDevNames.length ) {
int gameID = GameUtils.newGameID();
BTService.
inviteRemote( NewGameActivity.this,
m_btDevNames[m_chosen],
gameID, m_lang, 2, 1 );
startProgress( R.string.invite_progress );
}
}
}
};
ab = new AlertDialog.Builder( this )
.setTitle( R.string.bt_pick_title )
.setPositiveButton( R.string.button_ok, okLstnr )
.setNegativeButton( R.string.bt_pick_rescan_button,
scanLstnr );
if ( null != m_btDevNames && 0 < m_btDevNames.length ) {
OnClickListener devChosenLstnr =
new OnClickListener() {
public void onClick( DialogInterface dlgi,
int whichButton ) {
AlertDialog dlg = (AlertDialog)dlgi;
Button btn =
dlg.getButton( AlertDialog.BUTTON_POSITIVE );
btn.setEnabled( 0 <= whichButton );
m_chosen = whichButton;
}
};
m_chosen = -1;
ab.setSingleChoiceItems( m_btDevNames, m_chosen,
devChosenLstnr );
}
dialog = ab.create();
Utils.setRemoveOnDismiss( this, dialog, PICK_BTDEV_DLG );
break;
}
}
return dialog;
}
@Override
protected void onPrepareDialog( int id, Dialog dialog )
{
super.onPrepareDialog( id, dialog );
if ( PICK_BTDEV_DLG == id ) {
((AlertDialog)dialog).getButton( AlertDialog.BUTTON_POSITIVE )
.setEnabled( false );
}
}
// DlgDelegate.DlgClickNotify interface
@Override
public void dlgButtonClicked( int id, int which )
@ -209,50 +132,38 @@ public class NewGameActivity extends XWActivity {
protected void onActivityResult( int requestCode, int resultCode,
Intent data )
{
if ( CONFIG_BT == requestCode ) {
if ( Activity.RESULT_CANCELED == resultCode ) {
DBUtils.deleteGame( this, m_btRowID );
} else {
// We'll leave it up to BoardActivity to detect that
// it's not had any remote connections yet.
GameUtils.launchGame( this, m_btRowID );
finish();
if ( Activity.RESULT_CANCELED != resultCode ) {
switch ( requestCode ) {
case CONFIG_FOR_BT:
if ( Activity.RESULT_CANCELED == resultCode ) {
DBUtils.deleteGame( this, m_btRowID );
} else {
// We'll leave it up to BoardActivity to detect that
// it's not had any remote connections yet.
GameUtils.launchGame( this, m_btRowID );
finish();
}
break;
case INVITE_FOR_BT: // user selected device
if ( Activity.RESULT_CANCELED != resultCode ) {
int gameID = GameUtils.newGameID();
String[] remoteDevs =
data.getStringArrayExtra( BTInviteActivity.DEVS );
DbgUtils.logf( "got %s", remoteDevs[0] );
BTService.inviteRemote( NewGameActivity.this, remoteDevs[0],
gameID, m_lang, 2, 1 );
startProgress( R.string.invite_progress );
}
break;
}
}
}
@Override
protected void onSaveInstanceState( Bundle outState )
{
super.onSaveInstanceState( outState );
outState.putStringArray( SAVE_DEVNAMES, m_btDevNames );
}
private void getBundledData( Bundle bundle )
{
if ( null != bundle ) {
m_btDevNames = bundle.getStringArray( SAVE_DEVNAMES );
}
}
// BTService.BTEventListener interface
@Override
public void eventOccurred( BTService.BTEvent event, final Object ... args )
{
switch( event ) {
case SCAN_DONE:
m_handler.post( new Runnable() {
public void run() {
synchronized( NewGameActivity.this ) {
stopProgress();
if ( 0 < args.length ) {
m_btDevNames = (String[])(args[0]);
}
showDialog( PICK_BTDEV_DLG );
}
}
} );
break;
case BT_ENABLED:
case BT_DISABLED:
m_handler.post( new Runnable() {
@ -284,7 +195,7 @@ public class NewGameActivity extends XWActivity {
} );
break;
default:
DbgUtils.logf( "unexpected event %s", event.toString() );
super.eventOccurred( event, args );
break;
}
}
@ -341,12 +252,9 @@ public class NewGameActivity extends XWActivity {
intent.setAction( Intent.ACTION_EDIT );
intent.putExtra( GameUtils.INTENT_KEY_ROWID, m_btRowID );
intent.putExtra( GameUtils.INTENT_FORRESULT_ROWID, true );
startActivityForResult( intent, CONFIG_BT );
} else if ( null == m_btDevNames || 0 == m_btDevNames.length ) {
startProgress( R.string.scan_progress );
BTService.rescan( this );
startActivityForResult( intent, CONFIG_FOR_BT );
} else {
showDialog( PICK_BTDEV_DLG );
GameUtils.launchBTInviter( this, 1, INVITE_FOR_BT );
}
}

View file

@ -30,7 +30,7 @@ import junit.framework.Assert;
import org.eehouse.android.xw4.jni.CommonPrefs;
public class XWListActivity extends ListActivity
implements DlgDelegate.DlgClickNotify {
implements DlgDelegate.DlgClickNotify, BTService.BTEventListener {
private DlgDelegate m_delegate;
@ -54,6 +54,7 @@ public class XWListActivity extends ListActivity
protected void onResume()
{
DbgUtils.logf( "%s.onResume(this=%H)", getClass().getName(), this );
BTService.setBTEventListener( this );
super.onResume();
}
@ -61,6 +62,7 @@ public class XWListActivity extends ListActivity
protected void onPause()
{
DbgUtils.logf( "%s.onPause(this=%H)", getClass().getName(), this );
BTService.setBTEventListener( null );
super.onPause();
}
@ -157,6 +159,16 @@ public class XWListActivity extends ListActivity
m_delegate.doSyncMenuitem();
}
protected void startProgress( int id )
{
m_delegate.startProgress( id );
}
protected void stopProgress()
{
m_delegate.stopProgress();
}
// DlgDelegate.DlgClickNotify interface
public void dlgButtonClicked( int id, int which )
{
@ -173,4 +185,10 @@ public class XWListActivity extends ListActivity
m_delegate.launchLookup( words, lang, forceList );
}
// BTService.BTEventListener interface
public void eventOccurred( BTService.BTEvent event, final Object ... args )
{
m_delegate.eventOccurred( event, args );
}
}

View file

@ -108,6 +108,9 @@ public interface UtilCtxt {
void informMove( String expl, String words );
void informMissing( boolean isServer, CommsAddrRec.CommsConnType connType,
int nMissingPlayers );
void notifyGameOver();
// Don't need this unless we have a scroll thumb to indicate position
//void yOffsetChange( int maxOffset, int oldOffset, int newOffset );

View file

@ -207,6 +207,13 @@ public class UtilCtxtImpl implements UtilCtxt {
subclassOverride( "informMove" );
}
public void informMissing( boolean isServer,
CommsAddrRec.CommsConnType connType,
int nMissingPlayers )
{
subclassOverride( "informMissing" );
}
// Probably want to cache the fact that the game over notification
// showed up and then display it next time game's opened.
public void notifyGameOver()