package com.door43.translationstudio.service; import android.content.Intent; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import com.door43.tools.reporting.Logger; import com.door43.translationstudio.network.BroadcastListenerRunnable; import com.door43.translationstudio.network.Peer; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; import java.util.Timer; import java.util.TimerTask; /** * This class listens for services being broadcasted on the local network. * Notifications are fired whenever a service becomes or is no longer available. */ public class BroadcastListenerService extends NetworkService { public static final String PARAM_SERVER_TTL = "param_server_ttl"; public static final String PARAM_REFRESH_FREQUENCY = "param_refresh_frequency"; public static final String PARAM_BROADCAST_PORT = "param_broadcast_udp_port"; private final IBinder mBinder = new LocalBinder(); private Thread mBroadcastListenerThread; private BroadcastListenerRunnable mBroadcastListenerRunnable; private Callbacks mListener; private Timer mCleanupTimer; private static Boolean mIsRunning = false; /** * Sets whether or not the service is running * @param running */ protected void setRunning(Boolean running) { mIsRunning = running; } /** * Checks if the service is currently running * @return */ public static boolean isRunning() { return mIsRunning; } @Override public IBinder onBind(Intent intent) { return mBinder; } public void registerCallback(Callbacks callback) { mListener = callback; } @Override public void onCreate() { Logger.i(this.getClass().getName(), "Starting broadcast listener"); mCleanupTimer = new Timer(); } @Override public int onStartCommand(Intent intent, int flags, int startid) { if(intent != null) { Bundle args = intent.getExtras(); if (args != null && args.containsKey(PARAM_BROADCAST_PORT)) { final int UDPport = args.getInt(PARAM_BROADCAST_PORT); final int serverTTL = args.getInt(PARAM_SERVER_TTL, 10000); final int refreshFrequency = args.getInt(PARAM_REFRESH_FREQUENCY, 5000); // listener thread mBroadcastListenerRunnable = new BroadcastListenerRunnable(UDPport, new BroadcastListenerRunnable.OnBroadcastListenerEventListener() { @Override public void onError(Exception e) { Logger.e(BroadcastListenerService.class.getName(), "Broadcast listener encountered an exception", e); } @Override public void onMessageReceived(String message, String senderIP) { int version = -1; int port; try { JSONObject json = new JSONObject(message); version = json.getInt("version"); port = json.getInt("port"); } catch (JSONException e) { Logger.w(BroadcastListenerService.class.getName(), "Invalid message format " + message, e); return; } // validate protocol version if(version == BroadcastService.TS_PROTOCAL_VERSION) { Peer p = new Peer(senderIP, port, "tS", version); if(addPeer(p) && mListener != null) { mListener.onFoundServer(p); } } else { Logger.w(BroadcastListenerService.class.getName(), "Unsupported tS protocal version " + version); } } }); mBroadcastListenerThread = new Thread(mBroadcastListenerRunnable); mBroadcastListenerThread.start(); // cleanup task mCleanupTimer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { ArrayList<Peer> connectedPeers = getPeers(); for (Peer p : connectedPeers) { if (System.currentTimeMillis() - p.getLastSeenAt() > serverTTL) { removePeer(p); if(mListener != null) { mListener.onLostServer(p); } } } } }, 0, refreshFrequency); setRunning(true); return START_STICKY; } } Logger.e(this.getClass().getName(), "Broadcast listener service requires arguments"); stopService(); return START_NOT_STICKY; } @Override public void onDestroy() { stopService(); } /** * Stops the service */ private void stopService() { if(mBroadcastListenerThread != null) { mBroadcastListenerThread.interrupt(); } if(mBroadcastListenerRunnable != null) { mBroadcastListenerRunnable.stop(); } setRunning(false); Logger.i(this.getClass().getName(), "Stopping broadcast listener"); } public interface Callbacks { void onFoundServer(Peer server); @Deprecated void onLostServer(Peer server); } /** * Class to retrieve instance of service */ public class LocalBinder extends Binder { public BroadcastListenerService getServiceInstance() { return BroadcastListenerService.this; } } }