make RelayService descend from JobIntentService

Required moving most of XWService into a class to which all services
could delegate what they used to inherit.

squash me
This commit is contained in:
Eric House 2018-12-07 16:56:45 -08:00
parent 5f7e4aa1b9
commit c5c081e8bd
8 changed files with 362 additions and 269 deletions

View file

@ -25,6 +25,7 @@
<uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- Required for wifi-direct --> <!-- Required for wifi-direct -->
<!-- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> --> <!-- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> -->
@ -189,6 +190,7 @@
/> />
<service android:name="RelayService" <service android:name="RelayService"
android:exported="false" android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE"
/> />
<receiver android:name=".MountEventReceiver"> <receiver android:name=".MountEventReceiver">

View file

@ -191,6 +191,7 @@ public class BTService extends XWService {
private BTSenderThread m_sender; private BTSenderThread m_sender;
private Notification m_notification; // make once use many private Notification m_notification; // make once use many
private Handler mHandler; private Handler mHandler;
private BTServiceHelper mHelper;
private static int s_errCount = 0; private static int s_errCount = 0;
@ -418,6 +419,8 @@ public class BTService extends XWService {
Log.d( TAG, "%s.onCreate()", this ); Log.d( TAG, "%s.onCreate()", this );
super.onCreate(); super.onCreate();
mHelper = new BTServiceHelper( this );
m_btMsgSink = new BTMsgSink(); m_btMsgSink = new BTMsgSink();
mHandler = new Handler(); mHandler = new Handler();
startForegroundIf(); startForegroundIf();
@ -522,7 +525,7 @@ public class BTService extends XWService {
boolean cameOn = intent.getBooleanExtra( RADIO_KEY, false ); boolean cameOn = intent.getBooleanExtra( RADIO_KEY, false );
MultiEvent evt = cameOn? MultiEvent.BT_ENABLED MultiEvent evt = cameOn? MultiEvent.BT_ENABLED
: MultiEvent.BT_DISABLED; : MultiEvent.BT_DISABLED;
postEvent( evt ); mHelper.postEvent( evt );
if ( cameOn ) { if ( cameOn ) {
GameUtils.resendAllIf( this, CommsConnType.COMMS_CONN_BT ); GameUtils.resendAllIf( this, CommsConnType.COMMS_CONN_BT );
} else { } else {
@ -581,6 +584,7 @@ public class BTService extends XWService {
private BluetoothServerSocket m_serverSocket; private BluetoothServerSocket m_serverSocket;
private Context mContext; private Context mContext;
private BTService mService; private BTService mService;
private BTServiceHelper mHelper;
private volatile Thread mTimerThread; private volatile Thread mTimerThread;
private BTListenerThread( Context context, BTService service ) private BTListenerThread( Context context, BTService service )
@ -595,7 +599,8 @@ public class BTService extends XWService {
} }
} }
static void startYourself( Context context, BTService service ) static void startYourself( Context context, BTService service,
BTServiceHelper helper )
{ {
Log.d( TAG, "startYourself(%s, %s)", context, service ); Log.d( TAG, "startYourself(%s, %s)", context, service );
DbgUtils.assertOnUIThread(); DbgUtils.assertOnUIThread();
@ -604,7 +609,7 @@ public class BTService extends XWService {
s_listener[0] = new BTListenerThread( context, service ); s_listener[0] = new BTListenerThread( context, service );
s_listener[0].start(); s_listener[0].start();
} else if ( null != service ) { } else if ( null != service ) {
s_listener[0].setService( context, service ); s_listener[0].setService( context, service, helper );
} }
} }
} }
@ -612,7 +617,7 @@ public class BTService extends XWService {
static void startYourself( Context context ) static void startYourself( Context context )
{ {
DbgUtils.assertOnUIThread(); DbgUtils.assertOnUIThread();
startYourself( context, null ); startYourself( context, null, null );
} }
static void stopYourself( BTListenerThread self ) static void stopYourself( BTListenerThread self )
@ -634,11 +639,12 @@ public class BTService extends XWService {
} }
} }
void setService( Context context, BTService service ) void setService( Context context, BTService service, BTServiceHelper helper )
{ {
if ( null == mService ) { if ( null == mService ) {
Log.d( TAG, "setService(): we didn't have one before. Do something!!!" ); Log.d( TAG, "setService(): we didn't have one before. Do something!!!" );
mService = service; mService = service;
mHelper = helper;
Assert.assertNotNull( context ); Assert.assertNotNull( context );
mContext = context; // Use Service instead of Receiver (possibly) mContext = context; // Use Service instead of Receiver (possibly)
} else { } else {
@ -838,16 +844,16 @@ public class BTService extends XWService {
CommsAddrRec addr = new CommsAddrRec( host.getName(), CommsAddrRec addr = new CommsAddrRec( host.getName(),
host.getAddress() ); host.getAddress() );
ReceiveResult rslt XWServiceHelper.ReceiveResult rslt
= mService.receiveMessage( mContext, = mHelper.receiveMessage( mContext,
gameID, mService.m_btMsgSink, gameID, mService.m_btMsgSink,
buffer, addr ); buffer, addr );
result = rslt == ReceiveResult.GAME_GONE ? result = rslt == XWServiceHelper.ReceiveResult.GAME_GONE ?
BTCmd.MESG_GAMEGONE : BTCmd.MESG_ACCPT; BTCmd.MESG_GAMEGONE : BTCmd.MESG_ACCPT;
break; break;
case MESG_GAMEGONE: case MESG_GAMEGONE:
mService.postEvent( MultiEvent.MESSAGE_NOGAME, gameID ); mHelper.postEvent( MultiEvent.MESSAGE_NOGAME, gameID );
result = BTCmd.MESG_ACCPT; result = BTCmd.MESG_ACCPT;
break; break;
default: default:
@ -977,7 +983,7 @@ public class BTService extends XWService {
addrs.add( dev ); addrs.add( dev );
} }
if ( null != event ) { if ( null != event ) {
postEvent( event, dev.getName() ); mHelper.postEvent( event, dev.getName() );
} }
} }
} else { } else {
@ -1010,7 +1016,7 @@ public class BTService extends XWService {
} else { } else {
gotReply = BTCmd.PONG == reply; gotReply = BTCmd.PONG == reply;
if ( gotReply && is.readBoolean() ) { if ( gotReply && is.readBoolean() ) {
postEvent( MultiEvent.MESSAGE_NOGAME, gameID ); mHelper.postEvent( MultiEvent.MESSAGE_NOGAME, gameID );
} }
} }
@ -1064,20 +1070,24 @@ public class BTService extends XWService {
} }
if ( null == reply ) { if ( null == reply ) {
postEvent( MultiEvent.APP_NOT_FOUND_BT, dev.getName() ); mHelper.postEvent( MultiEvent.APP_NOT_FOUND_BT,
dev.getName() );
} else { } else {
switch ( reply ) { switch ( reply ) {
case BAD_PROTO: case BAD_PROTO:
sendBadProto( socket ); sendBadProto( socket );
break; break;
case INVITE_ACCPT: case INVITE_ACCPT:
postEvent( MultiEvent.NEWGAME_SUCCESS, elem.m_gameID ); mHelper.postEvent( MultiEvent.NEWGAME_SUCCESS,
elem.m_gameID );
break; break;
case INVITE_DUPID: case INVITE_DUPID:
postEvent( MultiEvent.NEWGAME_DUP_REJECTED, dev.getName() ); mHelper.postEvent( MultiEvent.NEWGAME_DUP_REJECTED,
dev.getName() );
break; break;
default: default:
postEvent( MultiEvent.NEWGAME_FAILURE, elem.m_gameID ); mHelper.postEvent( MultiEvent.NEWGAME_FAILURE,
elem.m_gameID );
break; break;
} }
} }
@ -1160,10 +1170,10 @@ public class BTService extends XWService {
if ( null != evt ) { if ( null != evt ) {
String btName = nameForAddr( m_adapter, elem.m_btAddr ); String btName = nameForAddr( m_adapter, elem.m_btAddr );
postEvent( evt, elem.m_gameID, 0, btName ); mHelper.postEvent( evt, elem.m_gameID, 0, btName );
if ( ! success ) { if ( ! success ) {
int failCount = elem.incrFailCount(); int failCount = elem.incrFailCount();
postEvent( MultiEvent.MESSAGE_RESEND, btName, mHelper.postEvent( MultiEvent.MESSAGE_RESEND, btName,
RESEND_TIMEOUT, failCount ); RESEND_TIMEOUT, failCount );
} }
} }
@ -1183,7 +1193,7 @@ public class BTService extends XWService {
iter.remove(); iter.remove();
} else if ( elem.failCountExceeded() ) { } else if ( elem.failCountExceeded() ) {
String btName = nameForAddr( m_adapter, elem.m_btAddr ); String btName = nameForAddr( m_adapter, elem.m_btAddr );
postEvent( MultiEvent.MESSAGE_FAILOUT, btName ); mHelper.postEvent( MultiEvent.MESSAGE_FAILOUT, btName );
iter.remove(); iter.remove();
} }
} }
@ -1241,12 +1251,13 @@ public class BTService extends XWService {
btNames[ii] = nameForAddr( m_adapter, btAddrs[ii] ); btNames[ii] = nameForAddr( m_adapter, btAddrs[ii] );
++ii; ++ii;
} }
postEvent( MultiEvent.SCAN_DONE, (Object)btAddrs, (Object)btNames ); mHelper.postEvent( MultiEvent.SCAN_DONE, (Object)btAddrs, (Object)btNames );
} }
private void startListener() private void startListener()
{ {
BTListenerThread.startYourself( this, this ); Assert.assertNotNull( mHelper );
BTListenerThread.startYourself( this, this, mHelper );
} }
private void startSender() private void startSender()
@ -1271,28 +1282,12 @@ public class BTService extends XWService {
m_sender = null; m_sender = null;
} }
@Override
void postNotification( String device, int gameID, long rowid )
{
String body = LocUtils.getString( this, R.string.new_bt_body_fmt,
device );
GameUtils.postInvitedNotification( this, gameID, body, rowid );
postEvent( MultiEvent.BT_GAME_CREATED, rowid );
}
@Override
MultiMsgSink getSink( long rowid )
{
return m_btMsgSink;
}
private BTCmd makeOrNotify( NetLaunchInfo nli, String btName, private BTCmd makeOrNotify( NetLaunchInfo nli, String btName,
String btAddr ) String btAddr )
{ {
BTCmd result; BTCmd result;
if ( handleInvitation( nli, btName, DictFetchOwner.OWNER_BT ) ) { // here if ( mHelper.handleInvitation( nli, btName,
DictFetchOwner.OWNER_BT ) ) {
result = BTCmd.INVITE_ACCPT; result = BTCmd.INVITE_ACCPT;
} else { } else {
result = BTCmd.INVITE_DUP_INVITE; // dupe of rematch result = BTCmd.INVITE_DUP_INVITE; // dupe of rematch
@ -1380,7 +1375,8 @@ public class BTService extends XWService {
private void sendBadProto( BluetoothSocket socket ) private void sendBadProto( BluetoothSocket socket )
{ {
postEvent( MultiEvent.BAD_PROTO_BT, socket.getRemoteDevice().getName() ); mHelper.postEvent( MultiEvent.BAD_PROTO_BT,
socket.getRemoteDevice().getName() );
} }
private void updateStatusOut( boolean success ) private void updateStatusOut( boolean success )
@ -1446,4 +1442,30 @@ public class BTService extends XWService {
return nSent; return nSent;
} }
} }
private class BTServiceHelper extends XWServiceHelper {
private Service mService;
BTServiceHelper( Service service ) {
super( service );
mService = service;
}
@Override
MultiMsgSink getSink( long rowid )
{
return m_btMsgSink;
}
@Override
void postNotification( String device, int gameID, long rowid )
{
String body = LocUtils.getString( mService, R.string.new_bt_body_fmt,
device );
GameUtils.postInvitedNotification( mService, gameID, body, rowid );
postEvent( MultiEvent.BT_GAME_CREATED, rowid );
}
}
} }

View file

@ -143,14 +143,14 @@ public class DelegateBase implements DlgClickNotify,
protected void onResume() protected void onResume()
{ {
m_isVisible = true; m_isVisible = true;
XWService.setListener( this ); XWServiceHelper.setListener( this );
runIfVisible(); runIfVisible();
} }
protected void onPause() protected void onPause()
{ {
m_isVisible = false; m_isVisible = false;
XWService.setListener( null ); XWServiceHelper.setListener( null );
} }
protected DelegateBase curThis() protected DelegateBase curThis()

View file

@ -25,9 +25,9 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Build; import android.os.Build;
import android.os.Handler; import android.os.Handler;
import android.support.v4.app.JobIntentService;
import android.text.TextUtils; import android.text.TextUtils;
import org.eehouse.android.xw4.GameUtils.BackMoveResult; import org.eehouse.android.xw4.GameUtils.BackMoveResult;
import org.eehouse.android.xw4.MultiService.DictFetchOwner; import org.eehouse.android.xw4.MultiService.DictFetchOwner;
import org.eehouse.android.xw4.MultiService.MultiEvent; import org.eehouse.android.xw4.MultiService.MultiEvent;
@ -62,7 +62,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
public class RelayService extends XWService public class RelayService extends JobIntentService
implements NetStateCache.StateChangedIf { implements NetStateCache.StateChangedIf {
private static final String TAG = RelayService.class.getSimpleName(); private static final String TAG = RelayService.class.getSimpleName();
private static final int MAX_SEND = 1024; private static final int MAX_SEND = 1024;
@ -121,6 +121,7 @@ public class RelayService extends XWService
private long m_lastGamePacketReceived; private long m_lastGamePacketReceived;
private int m_nativeFailScore; private int m_nativeFailScore;
private boolean m_skipUPDSet; private boolean m_skipUPDSet;
private RelayServiceHelper mHelper;
private static DevIDType s_curType = DevIDType.ID_TYPE_NONE; private static DevIDType s_curType = DevIDType.ID_TYPE_NONE;
private static long s_regStartTime = 0; private static long s_regStartTime = 0;
@ -221,20 +222,17 @@ public class RelayService extends XWService
public static void startService( Context context ) public static void startService( Context context )
{ {
Log.i( TAG, "startService()" );
Intent intent = getIntentTo( context, MsgCmds.UDP_CHANGED ); Intent intent = getIntentTo( context, MsgCmds.UDP_CHANGED );
startService( context, intent ); startService( context, intent );
} }
// Must use the same lobID for all work enqueued for the same class
private final static int sJobID = RelayService.class.hashCode();
private static void startService( Context context, Intent intent ) private static void startService( Context context, Intent intent )
{ {
Log.d( TAG, "startService(%s)", intent ); Log.d( TAG, "startService(%s) (calling enqueueWork())", intent );
enqueueWork( context, RelayService.class, sJobID, intent );
if ( inForeground() || Build.VERSION.SDK_INT < Build.VERSION_CODES.O ) {
context.startService( intent );
} else {
Log.d( TAG, "startService(); not starting" );
}
} }
private static void stopService( Context context ) private static void stopService( Context context )
@ -308,18 +306,11 @@ public class RelayService extends XWService
{ {
Log.d( TAG, "receiveInvitation: got nli from %d: %s", srcDevID, Log.d( TAG, "receiveInvitation: got nli from %d: %s", srcDevID,
nli.toString() ); nli.toString() );
if ( !handleInvitation( nli, null, DictFetchOwner.OWNER_RELAY ) ) { if ( !mHelper.handleInvitation( nli, null, DictFetchOwner.OWNER_RELAY ) ) {
Log.d( TAG, "handleInvitation() failed" ); Log.d( TAG, "handleInvitation() failed" );
} }
} }
@Override
void postNotification( String device, int gameID, long rowid )
{
String body = LocUtils.getString( this, R.string.new_relay_body );
GameUtils.postInvitedNotification( this, gameID, body, rowid );
}
// Exists to get incoming data onto the main thread // Exists to get incoming data onto the main thread
private static void postData( Context context, long rowid, byte[] msg ) private static void postData( Context context, long rowid, byte[] msg )
{ {
@ -364,16 +355,12 @@ public class RelayService extends XWService
return intent; return intent;
} }
@Override
protected MultiMsgSink getSink( long rowid )
{
return new RelayMsgSink().setRowID( rowid );
}
@Override @Override
public void onCreate() public void onCreate()
{ {
Log.d( TAG, "onCreate()" );
super.onCreate(); super.onCreate();
mHelper = new RelayServiceHelper( this );
m_lastGamePacketReceived = m_lastGamePacketReceived =
XWPrefs.getPrefsLong( this, R.string.key_last_packet, XWPrefs.getPrefsLong( this, R.string.key_last_packet,
Utils.getCurSeconds() ); Utils.getCurSeconds() );
@ -398,6 +385,8 @@ public class RelayService extends XWService
@Override @Override
public int onStartCommand( Intent intent, int flags, int startId ) public int onStartCommand( Intent intent, int flags, int startId )
{ {
Log.d( TAG, "onStartCommand(%s)", intent );
super.onStartCommand( intent, flags, startId );
Integer result = handleCommand( intent ); Integer result = handleCommand( intent );
if ( null == result ) { if ( null == result ) {
@ -409,6 +398,13 @@ public class RelayService extends XWService
return result; return result;
} }
@Override
public void onHandleWork( Intent intent )
{
Log.d( TAG, "onHandleWork(%s)", intent );
/*void*/ handleCommand( intent );
}
@Override @Override
public void onDestroy() public void onDestroy()
{ {
@ -436,7 +432,7 @@ public class RelayService extends XWService
cmd = null; cmd = null;
} }
if ( null != cmd ) { if ( null != cmd ) {
// Log.d( TAG, "onStartCommand(): cmd=%s", cmd.toString() ); Log.d( TAG, "onStartCommand(): cmd=%s", cmd.toString() );
switch( cmd ) { switch( cmd ) {
case PROCESS_GAME_MSGS: case PROCESS_GAME_MSGS:
String[] relayIDs = new String[1]; String[] relayIDs = new String[1];
@ -483,7 +479,7 @@ public class RelayService extends XWService
String relayID = intent.getStringExtra( RELAY_ID ); String relayID = intent.getStringExtra( RELAY_ID );
sendNoConnMessage( rowid, relayID, msg ); sendNoConnMessage( rowid, relayID, msg );
} else { } else {
receiveMessage( this, rowid, null, msg, s_addr ); mHelper.receiveMessage( this, rowid, null, msg, s_addr );
} }
break; break;
case INVITE: case INVITE:
@ -621,8 +617,6 @@ public class RelayService extends XWService
private void stopUDPThreadsIf() private void stopUDPThreadsIf()
{ {
DbgUtils.assertOnUIThread();
UDPThreads threads = m_UDPThreadsRef.getAndSet( null ); UDPThreads threads = m_UDPThreadsRef.getAndSet( null );
if ( null != threads ) { if ( null != threads ) {
threads.stop(); threads.stop();
@ -648,7 +642,7 @@ public class RelayService extends XWService
Log.i( TAG, "relay unvailable for another %d seconds", Log.i( TAG, "relay unvailable for another %d seconds",
unavail ); unavail );
String str = getVLIString( dis ); String str = getVLIString( dis );
postEvent( MultiEvent.RELAY_ALERT, str ); mHelper.postEvent( MultiEvent.RELAY_ALERT, str );
break; break;
case XWPDEV_ALERT: case XWPDEV_ALERT:
str = getVLIString( dis ); str = getVLIString( dis );
@ -999,7 +993,7 @@ public class RelayService extends XWService
long rowid = rowIDs[ii]; long rowid = rowIDs[ii];
sink.setRowID( rowid ); sink.setRowID( rowid );
for ( byte[] msg : forOne ) { for ( byte[] msg : forOne ) {
receiveMessage( this, rowid, sink, msg, s_addr ); mHelper.receiveMessage( this, rowid, sink, msg, s_addr );
} }
} }
} }
@ -1728,6 +1722,28 @@ public class RelayService extends XWService
} }
} }
private class RelayServiceHelper extends XWServiceHelper {
private Service mService;
RelayServiceHelper( Service service ) {
super( service );
mService = service;
}
@Override
protected MultiMsgSink getSink( long rowid )
{
return new RelayMsgSink().setRowID( rowid );
}
@Override
void postNotification( String device, int gameID, long rowid )
{
String body = LocUtils.getString( mService, R.string.new_relay_body );
GameUtils.postInvitedNotification( mService, gameID, body, rowid );
}
}
// Exits only to exist, so instanceof can distinguish // Exits only to exist, so instanceof can distinguish
private class EOQPacketData extends PacketData {} private class EOQPacketData extends PacketData {}
} }

View file

@ -86,6 +86,7 @@ public class SMSService extends XWService {
private BroadcastReceiver m_sentReceiver; private BroadcastReceiver m_sentReceiver;
private BroadcastReceiver m_receiveReceiver; private BroadcastReceiver m_receiveReceiver;
private OnSharedPreferenceChangeListener m_prefsListener; private OnSharedPreferenceChangeListener m_prefsListener;
private SMSServiceHelper mHelper;
private int m_nReceived = 0; private int m_nReceived = 0;
private static int s_nSent = 0; private static int s_nSent = 0;
@ -277,15 +278,10 @@ public class SMSService extends XWService {
return s_showToasts; return s_showToasts;
} }
@Override
protected MultiMsgSink getSink( long rowid )
{
return new SMSMsgSink( this );
}
@Override @Override
public void onCreate() public void onCreate()
{ {
mHelper = new SMSServiceHelper( this );
if ( Utils.deviceSupportsSMS( this ) ) { if ( Utils.deviceSupportsSMS( this ) ) {
registerReceivers(); registerReceivers();
} else { } else {
@ -469,10 +465,10 @@ public class SMSService extends XWService {
} }
break; break;
case DEATH: case DEATH:
postEvent( MultiEvent.MESSAGE_NOGAME, msg.gameID ); mHelper.postEvent( MultiEvent.MESSAGE_NOGAME, msg.gameID );
break; break;
case ACK_INVITE: case ACK_INVITE:
postEvent( MultiEvent.NEWGAME_SUCCESS, msg.gameID ); mHelper.postEvent( MultiEvent.NEWGAME_SUCCESS, msg.gameID );
break; break;
default: default:
Log.w( TAG, "unexpected cmd %s", msg.cmd ); Log.w( TAG, "unexpected cmd %s", msg.cmd );
@ -489,26 +485,17 @@ public class SMSService extends XWService {
for ( SMSProtoMsg msg : msgs ) { for ( SMSProtoMsg msg : msgs ) {
receive( msg, senderPhone ); receive( msg, senderPhone );
} }
postEvent( MultiEvent.SMS_RECEIVE_OK ); mHelper.postEvent( MultiEvent.SMS_RECEIVE_OK );
} else { } else {
Log.d( TAG, "receiveBuffer(): bogus or incomplete message from %s", Log.d( TAG, "receiveBuffer(): bogus or incomplete message from %s",
senderPhone ); senderPhone );
} }
} }
@Override
protected void postNotification( String phone, int gameID, long rowid )
{
String owner = Utils.phoneToContact( this, phone, true );
String body = LocUtils.getString( this, R.string.new_name_body_fmt,
owner );
GameUtils.postInvitedNotification( this, gameID, body, rowid );
}
private void makeForInvite( String phone, NetLaunchInfo nli ) private void makeForInvite( String phone, NetLaunchInfo nli )
{ {
if ( nli != null ) { if ( nli != null ) {
handleInvitation( nli, phone, DictFetchOwner.OWNER_SMS ); mHelper.handleInvitation( nli, phone, DictFetchOwner.OWNER_SMS );
ackInvite( phone, nli.gameID() ); ackInvite( phone, nli.gameID() );
} }
} }
@ -554,7 +541,7 @@ public class SMSService extends XWService {
} catch ( NullPointerException npe ) { } catch ( NullPointerException npe ) {
Assert.fail(); // shouldn't be trying to do this!!! Assert.fail(); // shouldn't be trying to do this!!!
} catch ( java.lang.SecurityException se ) { } catch ( java.lang.SecurityException se ) {
postEvent( MultiEvent.SMS_SEND_FAILED_NOPERMISSION ); mHelper.postEvent( MultiEvent.SMS_SEND_FAILED_NOPERMISSION );
} catch ( Exception ee ) { } catch ( Exception ee ) {
Log.ex( TAG, ee ); Log.ex( TAG, ee );
} }
@ -575,11 +562,12 @@ public class SMSService extends XWService {
private boolean feedMessage( int gameID, byte[] msg, CommsAddrRec addr ) private boolean feedMessage( int gameID, byte[] msg, CommsAddrRec addr )
{ {
ReceiveResult rslt = receiveMessage( this, gameID, null, msg, addr ); XWServiceHelper.ReceiveResult rslt = mHelper
if ( ReceiveResult.GAME_GONE == rslt ) { .receiveMessage( this, gameID, null, msg, addr );
if ( XWServiceHelper.ReceiveResult.GAME_GONE == rslt ) {
sendDiedPacket( addr.sms_phone, gameID ); sendDiedPacket( addr.sms_phone, gameID );
} }
return rslt == ReceiveResult.OK; return rslt == XWServiceHelper.ReceiveResult.OK;
} }
private void registerReceivers() private void registerReceivers()
@ -590,15 +578,15 @@ public class SMSService extends XWService {
{ {
switch ( getResultCode() ) { switch ( getResultCode() ) {
case Activity.RESULT_OK: case Activity.RESULT_OK:
postEvent( MultiEvent.SMS_SEND_OK ); mHelper.postEvent( MultiEvent.SMS_SEND_OK );
break; break;
case SmsManager.RESULT_ERROR_RADIO_OFF: case SmsManager.RESULT_ERROR_RADIO_OFF:
postEvent( MultiEvent.SMS_SEND_FAILED_NORADIO ); mHelper.postEvent( MultiEvent.SMS_SEND_FAILED_NORADIO );
break; break;
case SmsManager.RESULT_ERROR_NO_SERVICE: case SmsManager.RESULT_ERROR_NO_SERVICE:
default: default:
Log.w( TAG, "FAILURE!!!" ); Log.w( TAG, "FAILURE!!!" );
postEvent( MultiEvent.SMS_SEND_FAILED ); mHelper.postEvent( MultiEvent.SMS_SEND_FAILED );
break; break;
} }
} }
@ -655,4 +643,28 @@ public class SMSService extends XWService {
return sendPacket( addr.sms_phone, gameID, buf ); return sendPacket( addr.sms_phone, gameID, buf );
} }
} }
private class SMSServiceHelper extends XWServiceHelper {
private Service mService;
SMSServiceHelper( Service service ) {
super( service );
mService = service;
}
@Override
protected MultiMsgSink getSink( long rowid )
{
return new SMSMsgSink( SMSService.this );
}
@Override
protected void postNotification( String phone, int gameID, long rowid )
{
String owner = Utils.phoneToContact( mService, phone, true );
String body = LocUtils.getString( mService, R.string.new_name_body_fmt,
owner );
GameUtils.postInvitedNotification( mService, gameID, body, rowid );
}
}
} }

View file

@ -124,6 +124,7 @@ public class WiDirService extends XWService {
private static Set<String> s_peersSet; private static Set<String> s_peersSet;
private P2pMsgSink m_sink; private P2pMsgSink m_sink;
private WiDirServiceHelper mHelper;
public interface DevSetListener { public interface DevSetListener {
void setChanged( Map<String, String> macToName ); void setChanged( Map<String, String> macToName );
@ -133,6 +134,7 @@ public class WiDirService extends XWService {
public void onCreate() public void onCreate()
{ {
m_sink = new P2pMsgSink(); m_sink = new P2pMsgSink();
mHelper = new WiDirServiceHelper(this);
} }
@Override @Override
@ -751,8 +753,9 @@ public class WiDirService extends XWService {
CommsAddrRec addr = new CommsAddrRec( CommsConnType.COMMS_CONN_P2P ) CommsAddrRec addr = new CommsAddrRec( CommsConnType.COMMS_CONN_P2P )
.setP2PParams( macAddress ); .setP2PParams( macAddress );
ReceiveResult rslt = receiveMessage( this, gameID, m_sink, data, addr ); XWServiceHelper.ReceiveResult rslt = mHelper
if ( ReceiveResult.GAME_GONE == rslt ) { .receiveMessage( this, gameID, m_sink, data, addr );
if ( XWServiceHelper.ReceiveResult.GAME_GONE == rslt ) {
sendNoGame( null, macAddress, gameID ); sendNoGame( null, macAddress, gameID );
} }
} }
@ -764,27 +767,15 @@ public class WiDirService extends XWService {
NetLaunchInfo nli = NetLaunchInfo.makeFrom( this, nliData ); NetLaunchInfo nli = NetLaunchInfo.makeFrom( this, nliData );
String returnMac = intent.getStringExtra( KEY_SRC ); String returnMac = intent.getStringExtra( KEY_SRC );
if ( !handleInvitation( nli, returnMac, DictFetchOwner.OWNER_P2P ) ) { if ( !mHelper.handleInvitation( nli, returnMac, DictFetchOwner.OWNER_P2P ) ) {
Log.d( TAG, "handleInvitation() failed" ); Log.d( TAG, "handleInvitation() failed" );
} }
} }
@Override
void postNotification( String device, int gameID, long rowid )
{
Log.e( TAG, "postNotification() doing nothing" );
}
@Override
MultiMsgSink getSink( long rowid )
{
return m_sink;
}
private void handleGameGone( Intent intent ) private void handleGameGone( Intent intent )
{ {
int gameID = intent.getIntExtra( KEY_GAMEID, 0 ); int gameID = intent.getIntExtra( KEY_GAMEID, 0 );
postEvent( MultiEvent.MESSAGE_NOGAME, gameID ); mHelper.postEvent( MultiEvent.MESSAGE_NOGAME, gameID );
} }
private void makeGame( NetLaunchInfo nli, String senderMac ) private void makeGame( NetLaunchInfo nli, String senderMac )
@ -794,7 +785,7 @@ public class WiDirService extends XWService {
CommsAddrRec addr = nli.makeAddrRec( this ); CommsAddrRec addr = nli.makeAddrRec( this );
long rowid = GameUtils.makeNewMultiGame( this, nli, long rowid = GameUtils.makeNewMultiGame( this, nli,
m_sink, m_sink,
getUtilCtxt() ); mHelper.getUtilCtxt() );
if ( DBUtils.ROWID_NOTFOUND != rowid ) { if ( DBUtils.ROWID_NOTFOUND != rowid ) {
if ( null != nli.gameName && 0 < nli.gameName.length() ) { if ( null != nli.gameName && 0 < nli.gameName.length() ) {
DBUtils.setName( this, rowid, nli.gameName ); DBUtils.setName( this, rowid, nli.gameName );
@ -1206,4 +1197,23 @@ public class WiDirService extends XWService {
private class P2pMsgSink extends MultiMsgSink { private class P2pMsgSink extends MultiMsgSink {
public P2pMsgSink() { super( WiDirService.this ); } public P2pMsgSink() { super( WiDirService.this ); }
} }
private class WiDirServiceHelper extends XWServiceHelper {
WiDirServiceHelper( Service service ) {
super( service );
}
@Override
MultiMsgSink getSink( long rowid )
{
return m_sink;
}
@Override
void postNotification( String device, int gameID, long rowid )
{
Log.e( TAG, "postNotification() doing nothing" );
}
}
} }

View file

@ -1,6 +1,6 @@
/* -*- compile-command: "find-and-gradle.sh insXw4Deb"; -*- */ /* -*- compile-command: "find-and-gradle.sh insXw4Deb"; -*- */
/* /*
* Copyright 2010 - 2012 by Eric House (xwords@eehouse.org). All * Copyright 2010 - 2018 by Eric House (xwords@eehouse.org). All
* rights reserved. * rights reserved.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -21,166 +21,15 @@
package org.eehouse.android.xw4; package org.eehouse.android.xw4;
import android.app.Service; import android.app.Service;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.IBinder; import android.os.IBinder;
class XWService extends Service {
import org.eehouse.android.xw4.MultiService.DictFetchOwner;
import org.eehouse.android.xw4.MultiService.MultiEvent;
import org.eehouse.android.xw4.jni.CommsAddrRec;
import org.eehouse.android.xw4.jni.JNIThread;
import org.eehouse.android.xw4.jni.UtilCtxt;
import org.eehouse.android.xw4.jni.UtilCtxtImpl;
import java.util.HashMap;
import java.util.Map;
abstract class XWService extends Service {
private static final String TAG = XWService.class.getSimpleName(); private static final String TAG = XWService.class.getSimpleName();
public static enum ReceiveResult { OK, GAME_GONE, UNCONSUMED };
protected static MultiService s_srcMgr = null;
private static Map<String, Long> s_seen = new HashMap<>();
private UtilCtxt m_utilCtxt;
@Override @Override
public IBinder onBind( Intent intent ) public IBinder onBind( Intent intent )
{ {
return null; return null;
} }
public final static void setListener( MultiService.MultiEventListener li )
{
if ( null == s_srcMgr ) {
// DbgUtils.logf( "XWService.setListener: registering %s", li.getClass().getName() );
s_srcMgr = new MultiService();
}
s_srcMgr.setListener( li );
}
protected void postEvent( MultiEvent event, Object ... args )
{
if ( null != s_srcMgr ) {
s_srcMgr.postEvent( event, args );
} else {
Log.d( TAG, "postEvent(): dropping %s event",
event.toString() );
}
}
// Check that we aren't already processing an invitation with this
// inviteID.
private static final long SEEN_INTERVAL_MS = 1000 * 5;
private boolean checkNotDupe( NetLaunchInfo nli )
{
String inviteID = nli.inviteID();
synchronized( s_seen ) {
long now = System.currentTimeMillis();
Long lastSeen = s_seen.get( inviteID );
boolean seen = null != lastSeen && lastSeen + SEEN_INTERVAL_MS > now;
if ( !seen ) {
s_seen.put( inviteID, now );
}
Log.d( TAG, "checkNotDupe('%s') => %b", inviteID, !seen );
return !seen;
}
}
abstract void postNotification( String device, int gameID, long rowid );
// Return true if able to start game only
protected boolean handleInvitation( NetLaunchInfo nli, String device,
DictFetchOwner dfo )
{
boolean success = false;
long[] rowids = DBUtils.getRowIDsFor( this, nli.gameID() );
if ( 0 == rowids.length
|| ( rowids.length < nli.nPlayersT // will break for two-per-device game
&& XWPrefs.getSecondInviteAllowed( this ) ) ) {
if ( nli.isValid() && checkNotDupe( nli ) ) {
if ( DictLangCache.haveDict( this, nli.lang, nli.dict ) ) {
long rowid = GameUtils.makeNewMultiGame( this, nli,
getSink( 0 ),
getUtilCtxt() );
if ( null != nli.gameName && 0 < nli.gameName.length() ) {
DBUtils.setName( this, rowid, nli.gameName );
}
postNotification( device, nli.gameID(), rowid );
success = true;
} else {
Intent intent = MultiService
.makeMissingDictIntent( this, nli, dfo );
MultiService.postMissingDictNotification( this, intent,
nli.gameID() );
}
}
}
Log.d( TAG, "handleInvitation() => %b", success );
return success;
}
protected UtilCtxt getUtilCtxt()
{
if ( null == m_utilCtxt ) {
m_utilCtxt = new UtilCtxtImpl( this );
}
return m_utilCtxt;
}
// Meant to be overridden
abstract MultiMsgSink getSink( long rowid );
protected ReceiveResult receiveMessage( Context context, int gameID,
MultiMsgSink sink, byte[] msg,
CommsAddrRec addr )
{
ReceiveResult result;
long[] rowids = DBUtils.getRowIDsFor( context, gameID );
if ( null == rowids || 0 == rowids.length ) {
result = ReceiveResult.GAME_GONE;
} else {
result = ReceiveResult.UNCONSUMED;
for ( long rowid : rowids ) {
if ( receiveMessage( context, rowid, sink, msg, addr ) ) {
result = ReceiveResult.OK;
}
}
}
return result;
}
protected boolean receiveMessage( Context context, long rowid,
MultiMsgSink sink, byte[] msg,
CommsAddrRec addr )
{
boolean allConsumed = true;
boolean[] isLocalP = new boolean[1];
JNIThread jniThread = JNIThread.getRetained( rowid, false );
boolean consumed = false;
if ( null != jniThread ) {
consumed = true;
jniThread.receive( msg, addr ).release();
} else {
GameUtils.BackMoveResult bmr = new GameUtils.BackMoveResult();
if ( null == sink ) {
sink = getSink( rowid );
}
if ( GameUtils.feedMessage( context, rowid, msg, addr,
sink, bmr, isLocalP ) ) {
consumed = true;
GameUtils.postMoveNotification( context, rowid, bmr,
isLocalP[0] );
}
}
if ( allConsumed && !consumed ) {
allConsumed = false;
}
return allConsumed;
}
} }

View file

@ -0,0 +1,182 @@
/* -*- compile-command: "find-and-gradle.sh insXw4Deb"; -*- */
/*
* Copyright 2010 - 2018 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.Service;
import android.content.Context;
import android.content.Intent;
import org.eehouse.android.xw4.MultiService.DictFetchOwner;
import org.eehouse.android.xw4.MultiService.MultiEvent;
import org.eehouse.android.xw4.jni.CommsAddrRec;
import org.eehouse.android.xw4.jni.JNIThread;
import org.eehouse.android.xw4.jni.UtilCtxt;
import org.eehouse.android.xw4.jni.UtilCtxtImpl;
import java.util.HashMap;
import java.util.Map;
abstract class XWServiceHelper {
private static final String TAG = XWServiceHelper.class.getSimpleName();
private Service mService;
private static MultiService s_srcMgr = null;
public static enum ReceiveResult { OK, GAME_GONE, UNCONSUMED };
XWServiceHelper( Service service )
{
mService = service;
}
abstract MultiMsgSink getSink( long rowid );
abstract void postNotification( String device, int gameID, long rowid );
protected ReceiveResult receiveMessage( Context context, int gameID,
MultiMsgSink sink, byte[] msg,
CommsAddrRec addr )
{
ReceiveResult result;
long[] rowids = DBUtils.getRowIDsFor( context, gameID );
if ( null == rowids || 0 == rowids.length ) {
result = ReceiveResult.GAME_GONE;
} else {
result = ReceiveResult.UNCONSUMED;
for ( long rowid : rowids ) {
if ( receiveMessage( context, rowid, sink, msg, addr ) ) {
result = ReceiveResult.OK;
}
}
}
return result;
}
protected boolean receiveMessage( Context context, long rowid,
MultiMsgSink sink, byte[] msg,
CommsAddrRec addr )
{
boolean allConsumed = true;
boolean[] isLocalP = new boolean[1];
JNIThread jniThread = JNIThread.getRetained( rowid, false );
boolean consumed = false;
if ( null != jniThread ) {
consumed = true;
jniThread.receive( msg, addr ).release();
} else {
GameUtils.BackMoveResult bmr = new GameUtils.BackMoveResult();
if ( null == sink ) {
sink = getSink( rowid );
}
if ( GameUtils.feedMessage( context, rowid, msg, addr,
sink, bmr, isLocalP ) ) {
consumed = true;
GameUtils.postMoveNotification( context, rowid, bmr,
isLocalP[0] );
}
}
if ( allConsumed && !consumed ) {
allConsumed = false;
}
return allConsumed;
}
public final static void setListener( MultiService.MultiEventListener li )
{
if ( null == s_srcMgr ) {
// DbgUtils.logf( "XWService.setListener: registering %s",
// li.getClass().getName() );
s_srcMgr = new MultiService();
}
s_srcMgr.setListener( li );
}
protected void postEvent( MultiEvent event, Object ... args )
{
if ( null != s_srcMgr ) {
s_srcMgr.postEvent( event, args );
} else {
Log.d( TAG, "postEvent(): dropping %s event",
event.toString() );
}
}
protected boolean handleInvitation( NetLaunchInfo nli, String device,
DictFetchOwner dfo )
{
boolean success = false;
long[] rowids = DBUtils.getRowIDsFor( mService, nli.gameID() );
if ( 0 == rowids.length
|| ( rowids.length < nli.nPlayersT // will break for two-per-device game
&& XWPrefs.getSecondInviteAllowed( mService ) ) ) {
if ( nli.isValid() && checkNotDupe( nli ) ) {
if ( DictLangCache.haveDict( mService, nli.lang, nli.dict ) ) {
long rowid = GameUtils.makeNewMultiGame( mService, nli,
getSink( 0 ),
getUtilCtxt() );
if ( null != nli.gameName && 0 < nli.gameName.length() ) {
DBUtils.setName( mService, rowid, nli.gameName );
}
postNotification( device, nli.gameID(), rowid );
success = true;
} else {
Intent intent = MultiService
.makeMissingDictIntent( mService, nli, dfo );
MultiService.postMissingDictNotification( mService, intent,
nli.gameID() );
}
}
}
Log.d( TAG, "handleInvitation() => %b", success );
return success;
}
private UtilCtxt m_utilCtxt;
protected UtilCtxt getUtilCtxt()
{
if ( null == m_utilCtxt ) {
m_utilCtxt = new UtilCtxtImpl( mService );
}
return m_utilCtxt;
}
// Check that we aren't already processing an invitation with this
// inviteID.
private static final long SEEN_INTERVAL_MS = 1000 * 5;
private static Map<String, Long> s_seen = new HashMap<>();
private boolean checkNotDupe( NetLaunchInfo nli )
{
String inviteID = nli.inviteID();
synchronized( s_seen ) {
long now = System.currentTimeMillis();
Long lastSeen = s_seen.get( inviteID );
boolean seen = null != lastSeen && lastSeen + SEEN_INTERVAL_MS > now;
if ( !seen ) {
s_seen.put( inviteID, now );
}
Log.d( TAG, "checkNotDupe('%s') => %b", inviteID, !seen );
return !seen;
}
}
}