Handle invite to BT game via NFC.

This commit is contained in:
Eric House 2014-09-10 07:24:12 -07:00
parent 3b2a537e93
commit a08292a918
7 changed files with 294 additions and 102 deletions

View file

@ -112,3 +112,5 @@ ListDelegator.java
NagTurnReceiver.java
OnBootReceiver.java
HeaderWithExpander.java
AbsLaunchInfo.java
BTLaunchInfo.java

View file

@ -0,0 +1,87 @@
/* -*- compile-command: "find-and-ant.sh 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.content.Intent;
import android.os.Bundle;
import org.json.JSONException;
import org.json.JSONObject;
public class AbsLaunchInfo {
private static final String LANG = "abslaunchinfo_lang";
private static final String DICT = "abslaunchinfo_dict";
private static final String NPLAYERS = "abslaunchinfo_nplayers";
private static final String NPLAYERST = "abslaunchinfo_nplayerst";
private static final String VALID = "abslaunchinfo_valid";
protected String dict;
protected int lang;
protected int nPlayersT;
private boolean m_valid;
protected AbsLaunchInfo() {}
protected JSONObject init( String data ) throws JSONException
{
JSONObject json = new JSONObject( data );
lang = json.getInt( LANG );
dict = json.getString( DICT );
nPlayersT = json.getInt( NPLAYERST );
return json;
}
protected void init( Intent intent )
{
Bundle bundle = intent.getExtras();
init( bundle );
}
protected void init( Bundle bundle )
{
lang = bundle.getInt( LANG );
dict = bundle.getString( DICT );
nPlayersT = bundle.getInt( NPLAYERS );
m_valid = bundle.getBoolean( VALID );
}
protected void putSelf( Bundle bundle )
{
bundle.putInt( LANG, lang );
bundle.putString( DICT, dict );
bundle.putInt( NPLAYERS, nPlayersT );
bundle.putBoolean( VALID, m_valid );
}
protected static JSONObject makeLaunchJSONObject( int lang, String dict,
int nPlayersT )
throws JSONException
{
return new JSONObject()
.put( LANG, lang )
.put( DICT, dict )
.put( NPLAYERST, nPlayersT )
;
}
protected boolean isValid() { return m_valid; }
protected void setValid( boolean valid ) { m_valid = valid; }
}

View file

@ -0,0 +1,73 @@
/* -*- compile-command: "find-and-ant.sh 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.bluetooth.BluetoothAdapter;
import org.json.JSONObject;
import org.json.JSONException;
import android.content.Context;
public class BTLaunchInfo extends AbsLaunchInfo {
private static final String INVITE_GAMEID = "INVITE_GAMEID";
private static final String INVITE_BT_NAME = "INVITE_BT_NAME";
private static final String INVITE_BT_ADDRESS = "INVITE_BT_ADDRESS";
protected String btName;
protected String btAddress;
protected int gameID;
public BTLaunchInfo( String data )
{
try {
JSONObject json = init( data );
gameID = json.getInt( INVITE_GAMEID );
btName = json.getString( INVITE_BT_NAME );
btAddress = json.getString( INVITE_BT_ADDRESS );
setValid( true );
} catch ( JSONException ex ) {
DbgUtils.loge( ex );
}
}
public static String makeLaunchJSON( int gameID, int lang,
String dict, int nPlayersT )
{
String result = null;
BluetoothAdapter adapter = XWApp.BTSUPPORTED
? BluetoothAdapter.getDefaultAdapter() : null;
if ( null != adapter ) {
String name = adapter.getName();
String address = adapter.getAddress();
try {
result = makeLaunchJSONObject( lang, dict, nPlayersT )
.put( INVITE_GAMEID, gameID )
.put( INVITE_BT_NAME, name )
.put( INVITE_BT_ADDRESS, address )
.toString();
} catch ( org.json.JSONException jse ) {
DbgUtils.loge( jse );
}
}
return result;
}
}

View file

@ -64,6 +64,7 @@ public class BTService extends XWService {
private static final int RADIO = 4;
private static final int CLEAR = 5;
private static final int REMOVE = 6;
private static final int NFCINVITE = 7;
private static final String CMD_STR = "CMD";
private static final String MSG_STR = "MSG";
@ -79,6 +80,8 @@ public class BTService extends XWService {
private static final String DICT_STR = "DCT";
private static final String NTO_STR = "TOT";
private static final String NHE_STR = "HER";
private static final String BT_NAME_STR = "BT_NAME_STR";
private static final String BT_ADDRESS_STR = "BT_ADDRESS_STR";
private enum BTCmd {
PING,
@ -187,6 +190,19 @@ public class BTService extends XWService {
context.startService( intent );
}
public static void gotGameViaNFC( Context context, BTLaunchInfo bli )
{
Intent intent = getIntentTo( context, NFCINVITE );
intent.putExtra( GAMEID_STR, bli.gameID );
intent.putExtra( DICT_STR, bli.dict );
intent.putExtra( LANG_STR, bli.lang );
intent.putExtra( NTO_STR, bli.nPlayersT );
intent.putExtra( BT_NAME_STR, bli.btName );
intent.putExtra( BT_ADDRESS_STR, bli.btAddress );
context.startService( intent );
}
public static int enqueueFor( Context context, byte[] buf,
String targetName, String targetAddr,
int gameID )
@ -271,6 +287,18 @@ public class BTService extends XWService {
gameID, gameName, lang,
dict, nPlayersT, nPlayersH ) );
break;
case NFCINVITE:
gameID = intent.getIntExtra( GAMEID_STR, -1 );
lang = intent.getIntExtra( LANG_STR, -1 );
dict = intent.getStringExtra( DICT_STR );
nPlayersT = intent.getIntExtra( NTO_STR, -1 );
String btName = intent.getStringExtra( BT_NAME_STR );
String btAddress = intent.getStringExtra( BT_ADDRESS_STR );
/*(void)*/makeGame( this, gameID, null, lang, dict,
nPlayersT, 1, btName, btAddress );
break;
case SEND:
byte[] buf = intent.getByteArrayExtra( MSG_STR );
target = intent.getStringExtra( TARGET_STR );
@ -308,7 +336,7 @@ public class BTService extends XWService {
result = Service.START_STICKY_COMPATIBILITY;
}
return result;
}
} // onStartCommand()
private class BTListenerThread extends Thread {
private BluetoothServerSocket m_serverSocket;
@ -421,31 +449,9 @@ public class BTService extends XWService {
BluetoothDevice host = socket.getRemoteDevice();
addAddr( host );
long[] rowids = DBUtils.getRowIDsFor( BTService.this, gameID );
if ( null == rowids || 0 == rowids.length ) {
String sender = host.getName();
CommsAddrRec addr = new CommsAddrRec( sender, host.getAddress() );
long rowid = GameUtils.makeNewBTGame( context, gameID, addr,
lang, dict, nPlayersT,
nPlayersH );
if ( DBUtils.ROWID_NOTFOUND == rowid ) {
result = BTCmd.INVITE_FAILED;
} else {
if ( null != gameName && 0 < gameName.length() ) {
DBUtils.setName( context, rowid, gameName );
}
result = BTCmd.INVITE_ACCPT;
String body = LocUtils.getString( BTService.this,
R.string.new_bt_body_fmt,
sender );
postNotification( gameID, R.string.new_bt_title, body, rowid );
// m_sender.allowReuse( gameID );
// Now: can/should I open the game???
}
} else {
result = BTCmd.INVITE_DUPID;
}
result = makeGame( context, gameID, gameName, lang, dict,
nPlayersT, nPlayersH,
host.getName(), host.getAddress() );
DataOutputStream os = new DataOutputStream( socket.getOutputStream() );
os.writeByte( result.ordinal() );
@ -948,6 +954,35 @@ public class BTService extends XWService {
DbgUtils.logf( "stopSender done" );
}
private BTCmd makeGame( Context context, int gameID, String gameName,
int lang, String dict, int nPlayersT, int nPlayersH,
String sender, String senderAddress )
{
BTCmd result;
long[] rowids = DBUtils.getRowIDsFor( BTService.this, gameID );
if ( null == rowids || 0 == rowids.length ) {
CommsAddrRec addr = new CommsAddrRec( sender, senderAddress );
long rowid = GameUtils.makeNewBTGame( context, gameID, addr,
lang, dict, nPlayersT,
nPlayersH );
if ( DBUtils.ROWID_NOTFOUND == rowid ) {
result = BTCmd.INVITE_FAILED;
} else {
if ( null != gameName && 0 < gameName.length() ) {
DBUtils.setName( context, rowid, gameName );
}
result = BTCmd.INVITE_ACCPT;
String body = LocUtils.getString( BTService.this,
R.string.new_bt_body_fmt,
sender );
postNotification( gameID, R.string.new_bt_title, body, rowid );
}
} else {
result = BTCmd.INVITE_DUPID;
}
return result;
}
private DataOutputStream connect( BluetoothSocket socket, BTCmd cmd )
{
DbgUtils.logf( "connecting to %s to send %s",

View file

@ -113,7 +113,6 @@ public class BoardDelegate extends DelegateBase
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;
private boolean m_gameOver = false;
@ -132,6 +131,8 @@ public class BoardDelegate extends DelegateBase
private String m_pwdName;
private String m_getDict;
// Join these two!!!
private int m_nMissingPlayers = -1;
private int m_missing;
private boolean m_haveInvited = false;
private boolean m_overNotShown;
@ -1164,13 +1165,25 @@ public class BoardDelegate extends DelegateBase
public String makeNFCMessage()
{
String data = null;
if ( 0 < m_missing ) { // Isn't there a better test??
String inviteID = String.format( "%X", m_gi.gameID );
String room = m_summary.roomName;
Assert.assertNotNull( room );
data = NetLaunchInfo.makeLaunchJSON( m_activity, room, inviteID,
m_gi.dictLang,
m_gi.dictName, m_gi.nPlayers );
switch ( m_connType ) {
case COMMS_CONN_RELAY:
if ( 0 < m_missing ) { // Isn't there a better test??
String room = m_summary.roomName;
String inviteID = String.format( "%X", m_gi.gameID );
Assert.assertNotNull( room );
data = NetLaunchInfo.makeLaunchJSON( room, inviteID, m_gi.dictLang,
m_gi.dictName, m_gi.nPlayers );
}
break;
case COMMS_CONN_BT:
if ( 0 < m_nMissingPlayers ) {
data = BTLaunchInfo.makeLaunchJSON( m_gi.gameID, m_gi.dictLang,
m_gi.dictName, m_gi.nPlayers );
}
break;
default:
DbgUtils.logf( "Not doing NFC join for conn type %s",
m_connType.toString() );
}
return data;
}

View file

@ -1588,10 +1588,18 @@ public class GamesListDelegate extends ListDelegateBase
{
String data = NFCUtils.getFromIntent( intent );
if ( null != data ) {
NetLaunchInfo nli = new NetLaunchInfo( data );
if ( nli.isValid() ) {
startNewNetGame( nli );
}
do {
NetLaunchInfo nli = new NetLaunchInfo( data );
if ( nli.isValid() ) {
startNewNetGame( nli );
break;
}
BTLaunchInfo bli = new BTLaunchInfo( data );
if ( bli.isValid() ) {
BTService.gotGameViaNFC( m_activity, bli );
break;
}
} while ( false );
}
}

View file

@ -28,64 +28,48 @@ import android.os.Bundle;
import java.net.URLEncoder;
import java.io.InputStream;
import org.json.JSONObject;
import org.json.JSONException;
import junit.framework.Assert;
import org.eehouse.android.xw4.loc.LocUtils;
public class NetLaunchInfo {
public String room;
public String inviteID;
public String dict;
public int lang;
public int nPlayersT;
public class NetLaunchInfo extends AbsLaunchInfo {
protected String room;
protected String inviteID;
private static final String LANG = "netlaunchinfo_lang";
private static final String ROOM = "netlaunchinfo_room";
private static final String DICT = "netlaunchinfo_dict";
private static final String INVITEID = "netlaunchinfo_inviteid";
private static final String NPLAYERS = "netlaunchinfo_nplayers";
private static final String VALID = "netlaunchinfo_valid";
private boolean m_valid;
public void putSelf( Bundle bundle )
{
bundle.putInt( LANG, lang );
bundle.putString( ROOM, room );
bundle.putString( INVITEID, inviteID );
bundle.putString( DICT, dict );
bundle.putInt( NPLAYERS, nPlayersT );
bundle.putBoolean( VALID, m_valid );
}
protected static final String INVITEID = "netlaunchinfo_inviteid";
protected static final String ROOM = "netlaunchinfo_room";
public NetLaunchInfo( String data )
{
try {
JSONObject json = new JSONObject( data );
room = json.getString( MultiService.ROOM );
inviteID = json.getString( MultiService.INVITEID );
lang = json.getInt( MultiService.LANG );
dict = json.getString( MultiService.DICT );
nPlayersT = json.getInt( MultiService.NPLAYERST );
m_valid = true;
} catch ( org.json.JSONException jse ) {
m_valid = false;
JSONObject json = init( data );
room = json.getString( ROOM );
inviteID = json.getString( INVITEID );
setValid( true );
} catch ( JSONException jse ) {
// Don't bother logging; it's just not a valid object of this type
}
}
public void putSelf( Bundle bundle )
{
super.putSelf( bundle );
bundle.putString( ROOM, room );
bundle.putString( INVITEID, inviteID );
}
public NetLaunchInfo( Bundle bundle )
{
lang = bundle.getInt( LANG );
init( bundle );
room = bundle.getString( ROOM );
dict = bundle.getString( DICT );
inviteID = bundle.getString( INVITEID );
nPlayersT = bundle.getInt( NPLAYERS );
m_valid = bundle.getBoolean( VALID );
}
public NetLaunchInfo( Context context, Uri data )
{
m_valid = false;
setValid( false );
if ( null != data ) {
String scheme = data.getScheme();
try {
@ -97,12 +81,9 @@ public class NetLaunchInfo {
byte[] buf = new byte[len];
is.read( buf );
JSONObject json = new JSONObject( new String( buf ) );
room = json.getString( MultiService.ROOM );
inviteID = json.getString( MultiService.INVITEID );
lang = json.getInt( MultiService.LANG );
dict = json.getString( MultiService.DICT );
nPlayersT = json.getInt( MultiService.NPLAYERST );
JSONObject json = init( new String( buf ) );
room = json.getString( ROOM );
inviteID = json.getString( INVITEID );
} else {
room = data.getQueryParameter( "room" );
inviteID = data.getQueryParameter( "id" );
@ -112,7 +93,7 @@ public class NetLaunchInfo {
String np = data.getQueryParameter( "np" );
nPlayersT = Integer.decode( np );
}
m_valid = true;
setValid( true );
} catch ( Exception e ) {
DbgUtils.logf( "unable to parse \"%s\"", data.toString() );
}
@ -121,14 +102,16 @@ public class NetLaunchInfo {
public NetLaunchInfo( Intent intent )
{
room = intent.getStringExtra( MultiService.ROOM );
inviteID = intent.getStringExtra( MultiService.INVITEID );
lang = intent.getIntExtra( MultiService.LANG, -1 );
dict = intent.getStringExtra( MultiService.DICT );
nPlayersT = intent.getIntExtra( MultiService.NPLAYERST, -1 );
m_valid = null != room
init( intent );
room = intent.getStringExtra( ROOM );
inviteID = intent.getStringExtra( INVITEID );
// lang = intent.getIntExtra( LANG, -1 );
// dict = intent.getStringExtra( DICT );
// nPlayersT = intent.getIntExtra( NPLAYERST, -1 );
boolean valid = null != room
&& -1 != lang
&& -1 != nPlayersT;
setValid( valid );
}
public static Uri makeLaunchUri( Context context, String room,
@ -150,27 +133,18 @@ public class NetLaunchInfo {
return ub.build();
}
public static String makeLaunchJSON( Context context, String room,
String inviteID, int lang,
public static String makeLaunchJSON( String room, String inviteID, int lang,
String dict, int nPlayersT )
{
String result = null;
try {
result = new JSONObject()
.put( MultiService.ROOM, room )
.put( MultiService.INVITEID, inviteID )
.put( MultiService.LANG, lang )
.put( MultiService.DICT, dict )
.put( MultiService.NPLAYERST, nPlayersT )
result = makeLaunchJSONObject( lang, dict, nPlayersT )
.put( ROOM, room )
.put( INVITEID, inviteID )
.toString();
} catch ( org.json.JSONException jse ) {
DbgUtils.loge( jse );
}
return result;
}
public boolean isValid()
{
return m_valid;
}
}