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

View file

@ -191,6 +191,7 @@ public class BTService extends XWService {
private BTSenderThread m_sender;
private Notification m_notification; // make once use many
private Handler mHandler;
private BTServiceHelper mHelper;
private static int s_errCount = 0;
@ -418,6 +419,8 @@ public class BTService extends XWService {
Log.d( TAG, "%s.onCreate()", this );
super.onCreate();
mHelper = new BTServiceHelper( this );
m_btMsgSink = new BTMsgSink();
mHandler = new Handler();
startForegroundIf();
@ -522,7 +525,7 @@ public class BTService extends XWService {
boolean cameOn = intent.getBooleanExtra( RADIO_KEY, false );
MultiEvent evt = cameOn? MultiEvent.BT_ENABLED
: MultiEvent.BT_DISABLED;
postEvent( evt );
mHelper.postEvent( evt );
if ( cameOn ) {
GameUtils.resendAllIf( this, CommsConnType.COMMS_CONN_BT );
} else {
@ -581,6 +584,7 @@ public class BTService extends XWService {
private BluetoothServerSocket m_serverSocket;
private Context mContext;
private BTService mService;
private BTServiceHelper mHelper;
private volatile Thread mTimerThread;
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 );
DbgUtils.assertOnUIThread();
@ -604,7 +609,7 @@ public class BTService extends XWService {
s_listener[0] = new BTListenerThread( context, service );
s_listener[0].start();
} 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 )
{
DbgUtils.assertOnUIThread();
startYourself( context, null );
startYourself( context, null, null );
}
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 ) {
Log.d( TAG, "setService(): we didn't have one before. Do something!!!" );
mService = service;
mHelper = helper;
Assert.assertNotNull( context );
mContext = context; // Use Service instead of Receiver (possibly)
} else {
@ -838,16 +844,16 @@ public class BTService extends XWService {
CommsAddrRec addr = new CommsAddrRec( host.getName(),
host.getAddress() );
ReceiveResult rslt
= mService.receiveMessage( mContext,
gameID, mService.m_btMsgSink,
buffer, addr );
XWServiceHelper.ReceiveResult rslt
= mHelper.receiveMessage( mContext,
gameID, mService.m_btMsgSink,
buffer, addr );
result = rslt == ReceiveResult.GAME_GONE ?
result = rslt == XWServiceHelper.ReceiveResult.GAME_GONE ?
BTCmd.MESG_GAMEGONE : BTCmd.MESG_ACCPT;
break;
case MESG_GAMEGONE:
mService.postEvent( MultiEvent.MESSAGE_NOGAME, gameID );
mHelper.postEvent( MultiEvent.MESSAGE_NOGAME, gameID );
result = BTCmd.MESG_ACCPT;
break;
default:
@ -977,7 +983,7 @@ public class BTService extends XWService {
addrs.add( dev );
}
if ( null != event ) {
postEvent( event, dev.getName() );
mHelper.postEvent( event, dev.getName() );
}
}
} else {
@ -1010,7 +1016,7 @@ public class BTService extends XWService {
} else {
gotReply = BTCmd.PONG == reply;
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 ) {
postEvent( MultiEvent.APP_NOT_FOUND_BT, dev.getName() );
mHelper.postEvent( MultiEvent.APP_NOT_FOUND_BT,
dev.getName() );
} else {
switch ( reply ) {
case BAD_PROTO:
sendBadProto( socket );
break;
case INVITE_ACCPT:
postEvent( MultiEvent.NEWGAME_SUCCESS, elem.m_gameID );
mHelper.postEvent( MultiEvent.NEWGAME_SUCCESS,
elem.m_gameID );
break;
case INVITE_DUPID:
postEvent( MultiEvent.NEWGAME_DUP_REJECTED, dev.getName() );
mHelper.postEvent( MultiEvent.NEWGAME_DUP_REJECTED,
dev.getName() );
break;
default:
postEvent( MultiEvent.NEWGAME_FAILURE, elem.m_gameID );
mHelper.postEvent( MultiEvent.NEWGAME_FAILURE,
elem.m_gameID );
break;
}
}
@ -1160,10 +1170,10 @@ public class BTService extends XWService {
if ( null != evt ) {
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 ) {
int failCount = elem.incrFailCount();
postEvent( MultiEvent.MESSAGE_RESEND, btName,
mHelper.postEvent( MultiEvent.MESSAGE_RESEND, btName,
RESEND_TIMEOUT, failCount );
}
}
@ -1183,7 +1193,7 @@ public class BTService extends XWService {
iter.remove();
} else if ( elem.failCountExceeded() ) {
String btName = nameForAddr( m_adapter, elem.m_btAddr );
postEvent( MultiEvent.MESSAGE_FAILOUT, btName );
mHelper.postEvent( MultiEvent.MESSAGE_FAILOUT, btName );
iter.remove();
}
}
@ -1241,12 +1251,13 @@ public class BTService extends XWService {
btNames[ii] = nameForAddr( m_adapter, btAddrs[ii] );
++ii;
}
postEvent( MultiEvent.SCAN_DONE, (Object)btAddrs, (Object)btNames );
mHelper.postEvent( MultiEvent.SCAN_DONE, (Object)btAddrs, (Object)btNames );
}
private void startListener()
{
BTListenerThread.startYourself( this, this );
Assert.assertNotNull( mHelper );
BTListenerThread.startYourself( this, this, mHelper );
}
private void startSender()
@ -1271,28 +1282,12 @@ public class BTService extends XWService {
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,
String btAddr )
{
BTCmd result;
if ( handleInvitation( nli, btName, DictFetchOwner.OWNER_BT ) ) { // here
if ( mHelper.handleInvitation( nli, btName,
DictFetchOwner.OWNER_BT ) ) {
result = BTCmd.INVITE_ACCPT;
} else {
result = BTCmd.INVITE_DUP_INVITE; // dupe of rematch
@ -1380,7 +1375,8 @@ public class BTService extends XWService {
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 )
@ -1446,4 +1442,30 @@ public class BTService extends XWService {
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()
{
m_isVisible = true;
XWService.setListener( this );
XWServiceHelper.setListener( this );
runIfVisible();
}
protected void onPause()
{
m_isVisible = false;
XWService.setListener( null );
XWServiceHelper.setListener( null );
}
protected DelegateBase curThis()

View file

@ -25,9 +25,9 @@ import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
import android.support.v4.app.JobIntentService;
import android.text.TextUtils;
import org.eehouse.android.xw4.GameUtils.BackMoveResult;
import org.eehouse.android.xw4.MultiService.DictFetchOwner;
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.AtomicReference;
public class RelayService extends XWService
public class RelayService extends JobIntentService
implements NetStateCache.StateChangedIf {
private static final String TAG = RelayService.class.getSimpleName();
private static final int MAX_SEND = 1024;
@ -121,6 +121,7 @@ public class RelayService extends XWService
private long m_lastGamePacketReceived;
private int m_nativeFailScore;
private boolean m_skipUPDSet;
private RelayServiceHelper mHelper;
private static DevIDType s_curType = DevIDType.ID_TYPE_NONE;
private static long s_regStartTime = 0;
@ -221,20 +222,17 @@ public class RelayService extends XWService
public static void startService( Context context )
{
Log.i( TAG, "startService()" );
Intent intent = getIntentTo( context, MsgCmds.UDP_CHANGED );
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 )
{
Log.d( TAG, "startService(%s)", intent );
if ( inForeground() || Build.VERSION.SDK_INT < Build.VERSION_CODES.O ) {
context.startService( intent );
} else {
Log.d( TAG, "startService(); not starting" );
}
Log.d( TAG, "startService(%s) (calling enqueueWork())", intent );
enqueueWork( context, RelayService.class, sJobID, intent );
}
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,
nli.toString() );
if ( !handleInvitation( nli, null, DictFetchOwner.OWNER_RELAY ) ) {
if ( !mHelper.handleInvitation( nli, null, DictFetchOwner.OWNER_RELAY ) ) {
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
private static void postData( Context context, long rowid, byte[] msg )
{
@ -364,16 +355,12 @@ public class RelayService extends XWService
return intent;
}
@Override
protected MultiMsgSink getSink( long rowid )
{
return new RelayMsgSink().setRowID( rowid );
}
@Override
public void onCreate()
{
Log.d( TAG, "onCreate()" );
super.onCreate();
mHelper = new RelayServiceHelper( this );
m_lastGamePacketReceived =
XWPrefs.getPrefsLong( this, R.string.key_last_packet,
Utils.getCurSeconds() );
@ -398,6 +385,8 @@ public class RelayService extends XWService
@Override
public int onStartCommand( Intent intent, int flags, int startId )
{
Log.d( TAG, "onStartCommand(%s)", intent );
super.onStartCommand( intent, flags, startId );
Integer result = handleCommand( intent );
if ( null == result ) {
@ -409,6 +398,13 @@ public class RelayService extends XWService
return result;
}
@Override
public void onHandleWork( Intent intent )
{
Log.d( TAG, "onHandleWork(%s)", intent );
/*void*/ handleCommand( intent );
}
@Override
public void onDestroy()
{
@ -436,7 +432,7 @@ public class RelayService extends XWService
cmd = null;
}
if ( null != cmd ) {
// Log.d( TAG, "onStartCommand(): cmd=%s", cmd.toString() );
Log.d( TAG, "onStartCommand(): cmd=%s", cmd.toString() );
switch( cmd ) {
case PROCESS_GAME_MSGS:
String[] relayIDs = new String[1];
@ -483,7 +479,7 @@ public class RelayService extends XWService
String relayID = intent.getStringExtra( RELAY_ID );
sendNoConnMessage( rowid, relayID, msg );
} else {
receiveMessage( this, rowid, null, msg, s_addr );
mHelper.receiveMessage( this, rowid, null, msg, s_addr );
}
break;
case INVITE:
@ -621,8 +617,6 @@ public class RelayService extends XWService
private void stopUDPThreadsIf()
{
DbgUtils.assertOnUIThread();
UDPThreads threads = m_UDPThreadsRef.getAndSet( null );
if ( null != threads ) {
threads.stop();
@ -648,7 +642,7 @@ public class RelayService extends XWService
Log.i( TAG, "relay unvailable for another %d seconds",
unavail );
String str = getVLIString( dis );
postEvent( MultiEvent.RELAY_ALERT, str );
mHelper.postEvent( MultiEvent.RELAY_ALERT, str );
break;
case XWPDEV_ALERT:
str = getVLIString( dis );
@ -999,7 +993,7 @@ public class RelayService extends XWService
long rowid = rowIDs[ii];
sink.setRowID( rowid );
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
private class EOQPacketData extends PacketData {}
}

View file

@ -86,6 +86,7 @@ public class SMSService extends XWService {
private BroadcastReceiver m_sentReceiver;
private BroadcastReceiver m_receiveReceiver;
private OnSharedPreferenceChangeListener m_prefsListener;
private SMSServiceHelper mHelper;
private int m_nReceived = 0;
private static int s_nSent = 0;
@ -277,15 +278,10 @@ public class SMSService extends XWService {
return s_showToasts;
}
@Override
protected MultiMsgSink getSink( long rowid )
{
return new SMSMsgSink( this );
}
@Override
public void onCreate()
{
mHelper = new SMSServiceHelper( this );
if ( Utils.deviceSupportsSMS( this ) ) {
registerReceivers();
} else {
@ -469,10 +465,10 @@ public class SMSService extends XWService {
}
break;
case DEATH:
postEvent( MultiEvent.MESSAGE_NOGAME, msg.gameID );
mHelper.postEvent( MultiEvent.MESSAGE_NOGAME, msg.gameID );
break;
case ACK_INVITE:
postEvent( MultiEvent.NEWGAME_SUCCESS, msg.gameID );
mHelper.postEvent( MultiEvent.NEWGAME_SUCCESS, msg.gameID );
break;
default:
Log.w( TAG, "unexpected cmd %s", msg.cmd );
@ -489,26 +485,17 @@ public class SMSService extends XWService {
for ( SMSProtoMsg msg : msgs ) {
receive( msg, senderPhone );
}
postEvent( MultiEvent.SMS_RECEIVE_OK );
mHelper.postEvent( MultiEvent.SMS_RECEIVE_OK );
} else {
Log.d( TAG, "receiveBuffer(): bogus or incomplete message from %s",
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 )
{
if ( nli != null ) {
handleInvitation( nli, phone, DictFetchOwner.OWNER_SMS );
mHelper.handleInvitation( nli, phone, DictFetchOwner.OWNER_SMS );
ackInvite( phone, nli.gameID() );
}
}
@ -554,7 +541,7 @@ public class SMSService extends XWService {
} catch ( NullPointerException npe ) {
Assert.fail(); // shouldn't be trying to do this!!!
} catch ( java.lang.SecurityException se ) {
postEvent( MultiEvent.SMS_SEND_FAILED_NOPERMISSION );
mHelper.postEvent( MultiEvent.SMS_SEND_FAILED_NOPERMISSION );
} catch ( Exception ee ) {
Log.ex( TAG, ee );
}
@ -575,11 +562,12 @@ public class SMSService extends XWService {
private boolean feedMessage( int gameID, byte[] msg, CommsAddrRec addr )
{
ReceiveResult rslt = receiveMessage( this, gameID, null, msg, addr );
if ( ReceiveResult.GAME_GONE == rslt ) {
XWServiceHelper.ReceiveResult rslt = mHelper
.receiveMessage( this, gameID, null, msg, addr );
if ( XWServiceHelper.ReceiveResult.GAME_GONE == rslt ) {
sendDiedPacket( addr.sms_phone, gameID );
}
return rslt == ReceiveResult.OK;
return rslt == XWServiceHelper.ReceiveResult.OK;
}
private void registerReceivers()
@ -590,15 +578,15 @@ public class SMSService extends XWService {
{
switch ( getResultCode() ) {
case Activity.RESULT_OK:
postEvent( MultiEvent.SMS_SEND_OK );
mHelper.postEvent( MultiEvent.SMS_SEND_OK );
break;
case SmsManager.RESULT_ERROR_RADIO_OFF:
postEvent( MultiEvent.SMS_SEND_FAILED_NORADIO );
mHelper.postEvent( MultiEvent.SMS_SEND_FAILED_NORADIO );
break;
case SmsManager.RESULT_ERROR_NO_SERVICE:
default:
Log.w( TAG, "FAILURE!!!" );
postEvent( MultiEvent.SMS_SEND_FAILED );
mHelper.postEvent( MultiEvent.SMS_SEND_FAILED );
break;
}
}
@ -655,4 +643,28 @@ public class SMSService extends XWService {
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 P2pMsgSink m_sink;
private WiDirServiceHelper mHelper;
public interface DevSetListener {
void setChanged( Map<String, String> macToName );
@ -133,6 +134,7 @@ public class WiDirService extends XWService {
public void onCreate()
{
m_sink = new P2pMsgSink();
mHelper = new WiDirServiceHelper(this);
}
@Override
@ -751,8 +753,9 @@ public class WiDirService extends XWService {
CommsAddrRec addr = new CommsAddrRec( CommsConnType.COMMS_CONN_P2P )
.setP2PParams( macAddress );
ReceiveResult rslt = receiveMessage( this, gameID, m_sink, data, addr );
if ( ReceiveResult.GAME_GONE == rslt ) {
XWServiceHelper.ReceiveResult rslt = mHelper
.receiveMessage( this, gameID, m_sink, data, addr );
if ( XWServiceHelper.ReceiveResult.GAME_GONE == rslt ) {
sendNoGame( null, macAddress, gameID );
}
}
@ -764,27 +767,15 @@ public class WiDirService extends XWService {
NetLaunchInfo nli = NetLaunchInfo.makeFrom( this, nliData );
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" );
}
}
@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 )
{
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 )
@ -794,7 +785,7 @@ public class WiDirService extends XWService {
CommsAddrRec addr = nli.makeAddrRec( this );
long rowid = GameUtils.makeNewMultiGame( this, nli,
m_sink,
getUtilCtxt() );
mHelper.getUtilCtxt() );
if ( DBUtils.ROWID_NOTFOUND != rowid ) {
if ( null != nli.gameName && 0 < nli.gameName.length() ) {
DBUtils.setName( this, rowid, nli.gameName );
@ -1206,4 +1197,23 @@ public class WiDirService extends XWService {
private class P2pMsgSink extends MultiMsgSink {
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"; -*- */
/*
* Copyright 2010 - 2012 by Eric House (xwords@eehouse.org). All
* Copyright 2010 - 2018 by Eric House (xwords@eehouse.org). All
* rights reserved.
*
* This program is free software; you can redistribute it and/or
@ -21,166 +21,15 @@
package org.eehouse.android.xw4;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
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 {
class XWService extends Service {
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
public IBinder onBind( Intent intent )
{
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;
}
}
}