package org.primftpd.services;
import android.annotation.TargetApi;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.net.nsd.NsdManager;
import android.net.nsd.NsdServiceInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.widget.Toast;
import org.greenrobot.eventbus.EventBus;
import org.primftpd.PrefsBean;
import org.primftpd.R;
import org.primftpd.ServerStateChangedEvent;
import org.primftpd.util.ServicesStartStopUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Abstract base class for {@link Service}s wrapping servers.
* <div>
* Implements:
* <ul>
* <li>android lifecycle</li>
* <li>statusbar notifications</li>
* <li>bonjour/zeroconf announcements</li>
* </ul>
* </div>
*
*/
public abstract class AbstractServerService
extends Service
{
protected static final int MSG_START = 1;
protected static final int MSG_STOP = 2;
protected final Logger logger = LoggerFactory.getLogger(getClass());
private Looper serviceLooper;
private ServerServiceHandler serviceHandler;
PrefsBean prefsBean;
private NsdManager.RegistrationListener nsdRegistrationListener;
protected abstract ServerServiceHandler createServiceHandler(
Looper serviceLooper,
AbstractServerService service);
protected abstract Object getServer();
protected abstract boolean launchServer();
protected abstract void stopServer();
protected abstract int getPort();
protected abstract String getServiceName();
protected void handleServerStartError(Exception e)
{
logger.error("could not start server", e);
String msg = getText(R.string.serverCouldNotBeStarted).toString();
msg += e.getLocalizedMessage();
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
HandlerThread thread = new HandlerThread(
"ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
serviceLooper = thread.getLooper();
serviceHandler = createServiceHandler(serviceLooper, this);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
logger.debug("onStartCommand()");
if (intent == null) {
logger.warn("intent is null in onStartCommand()");
return START_REDELIVER_INTENT;
}
// get parameters
Bundle extras = intent.getExtras();
prefsBean = (PrefsBean)extras.get(ServicesStartStopUtil.EXTRA_PREFS_BEAN);
// send start message (to handler)
Message msg = serviceHandler.obtainMessage();
msg.arg1 = MSG_START;
serviceHandler.sendMessage(msg);
// post event
EventBus.getDefault().post(new ServerStateChangedEvent());
// we don't want the system to kill the ftp server
//return START_NOT_STICKY;
return START_STICKY;
}
@Override
public void onDestroy() {
logger.debug("onDestroy()");
// send stop message (to handler)
Message msg = serviceHandler.obtainMessage();
msg.arg1 = MSG_STOP;
serviceHandler.sendMessage(msg);
// post event
EventBus.getDefault().post(new ServerStateChangedEvent());
}
/**
* Register a DNS-SD service (to be discoverable through Bonjour/Avahi).
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
protected void announceService () {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
nsdRegistrationListener = new NsdManager.RegistrationListener() {
@Override
public void onServiceRegistered(NsdServiceInfo serviceInfo) {
logger.debug("onServiceRegistered()");
}
@Override
public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
logger.debug("onRegistrationFailed()");
}
@Override
public void onServiceUnregistered(NsdServiceInfo serviceInfo) {
logger.debug("onServiceUnregistered()");
}
@Override
public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
logger.debug("onUnregistrationFailed()");
}
};
NsdServiceInfo serviceInfo = new NsdServiceInfo();
serviceInfo.setServiceName("primitive ftpd");
serviceInfo.setServiceType("_" + getServiceName() + "._tcp.");
serviceInfo.setPort(getPort());
NsdManager nsdManager = (NsdManager) getSystemService(Context.NSD_SERVICE);
nsdManager.registerService(
serviceInfo,
NsdManager.PROTOCOL_DNS_SD,
nsdRegistrationListener);
}
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
protected void unannounceService () {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
NsdManager nsdManager = (NsdManager) getSystemService(Context.NSD_SERVICE);
nsdManager.unregisterService(nsdRegistrationListener);
}
}
}