package it.geosolutions.geocollect.android.core.wmc.service;
import it.geosolutions.geocollect.android.app.BuildConfig;
import it.geosolutions.geocollect.android.app.R;
import it.geosolutions.geocollect.android.core.wmc.model.Configuration;
import it.geosolutions.geocollect.android.core.wmc.model.WMCCommand;
import it.geosolutions.geocollect.android.core.wmc.model.WMCReadResult;
import it.geosolutions.geocollect.android.core.wmc.service.events.RequestWMCDataEvent;
import it.geosolutions.geocollect.android.core.wmc.service.events.WMCCommunicationResultEvent;
import it.geosolutions.geocollect.android.core.wmc.service.events.WMCConnectionStateChangedEvent;
import it.geosolutions.geocollect.android.core.wmc.wmc.WMCFacade;
import it.geosolutions.geocollect.android.core.wmc.wmc.WMCMock;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import android.app.NotificationManager;
import android.app.Service;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
/**
* Created by Robert Oehler on 21.11.16.
*
*
*/
public class WMCService extends Service implements WMCFacade.ConnectionListener{
private final static String TAG = "WMCService";
public static final String PARAM_DEBUG = "PARAM_DEBUG";
public static final String PARAM_DEVICE = "PARAM_DEVICE";
public static final int NOTIFICATION_ID = 42;
private WMCFacade wmc;
private Handler handler;
private String deviceName;
@Override
public void onCreate() {
super.onCreate();
handler = new Handler();
EventBus.getDefault().register(this);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId){
final boolean debug = intent.getBooleanExtra(PARAM_DEBUG, false);
final BluetoothDevice device = intent.getParcelableExtra(PARAM_DEVICE);
if(debug) {
wmc = new WMCMock(this);
}else {
// not yet in this branch
//wmc = new WMCImpl(getBaseContext(), this);
}
new AsyncTask<Void,Void,Void>(){
@Override
protected Void doInBackground(Void... params) {
if (device != null) {
if(BuildConfig.DEBUG){
Log.i(TAG, "onStartCommand in Debug "+Boolean.toString(debug)+ " with device "+ device.toString());
}
wmc.connect(device);
} else {
Log.e(TAG, "no device to connect provided as parameter");
}
return null;
}
}.execute();
return Service.START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
/**
* receives @param RequestWMCDataEvent events
*
* They are handled in a background thread
* according to their command creating a response
* containing the result of the operation with the WMC
* this result is broadcasted
*
* @param event the event to handle
*/
@Subscribe
public void onEvent(final RequestWMCDataEvent event){
new AsyncTask<Void,Void, WMCCommunicationResultEvent>(){
@Override
protected WMCCommunicationResultEvent doInBackground(Void... params) {
WMCCommunicationResultEvent resultEvent = new WMCCommunicationResultEvent(event.getCommand());
switch (event.getCommand()){
case READ_CONFIG:
final Configuration configuration = wmc.readConfig();
if(configuration != null) {
resultEvent.setSuccess(true);
resultEvent.setConfiguration(configuration);
resultEvent.setDeviceName(deviceName);
}else{
Log.e(TAG, "error reading configuration from WMC");
}
break;
case WRITE_CONFIG:
if(event.getArg() != null && event.getArg() instanceof Configuration){
Configuration conf = (Configuration) event.getArg();
resultEvent.setSuccess(wmc.writeConfig(conf));
}else{
Log.e(TAG, "did not provide argument to write configuration to WMC");
}
break;
case READ_WATER:
WMCReadResult result = wmc.read();
if(result != null){
resultEvent.setSuccess(true);
resultEvent.setReadResult(result);
}else{
Log.e(TAG, "error reading water data from WMC");
}
break;
case RSSI:
boolean on = true;
if(event.getArg() != null && event.getArg() instanceof Boolean){
on = (Boolean) event.getArg();
}else{
Log.w(TAG, "did not provide argument to activate gsm on WMC, using \"on\"");
}
resultEvent.setSuccess(wmc.activateGSM(on));
break;
case TEST_SMS:
String testReceiver;
if(event.getArg() != null && event.getArg() instanceof String){
testReceiver = (String) event.getArg();
resultEvent.setSuccess(wmc.sendTestSMS(testReceiver));
}else{
Log.e(TAG, "did not provide argument recipient to send test sms request to WMC");
}
break;
case WRITE_TIME:
resultEvent.setSuccess(wmc.syncTime());
break;
case PRESET:
if(event.getArg() != null && event.getArg() instanceof String){
try {
double preset = Double.parseDouble((String) event.getArg());
resultEvent.setSuccess(wmc.presetOverallCounter(preset));
}catch (NumberFormatException e){
Log.e(TAG, "error parsing preset arg to double", e);
}
}else{
Log.e(TAG, "did not provide preset argument to write to WMC");
}
break;
case CLEAR_COUNTER:
if(event.getArg() != null && event.getArg() instanceof String){
try {
int week_day = Integer.parseInt((String) event.getArg());
resultEvent.setSuccess(wmc.clear(week_day));
}catch (NumberFormatException e){
Log.e(TAG, "error parsing week day arg to int", e);
}
}else{
Log.e(TAG, "did not provide week day argument to clear counter on WMC");
}
break;
case DISCONNECT:
boolean sysResetSuccessful = wmc.sendSysReset();
//wait
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Log.e(TAG, "delay failed");
}
if(!sysResetSuccessful){
Log.w(TAG, "sys reset failed");
}
//however, disconnect
wmc.disConnect();
//TODO report if an error occurred or ignore ?
resultEvent.setSuccess(true);
break;
}
return resultEvent;
}
@Override
protected void onPostExecute(WMCCommunicationResultEvent resultEvent) {
super.onPostExecute(resultEvent);
EventBus.getDefault().post(resultEvent);
}
}.execute();
}
@Override
public void onDeviceConnected(final String name) {
this.deviceName = name;
runOnUiThread(new Runnable() {
@Override
public void run() {
//state connected
WMCConnectionStateChangedEvent stateChangedEvent = new WMCConnectionStateChangedEvent(WMCConnectionStateChangedEvent.ConnectionState.CONNECTED);
stateChangedEvent.setWmcName(name);
EventBus.getDefault().post(stateChangedEvent);
showNotification(getString(R.string.state_connection_active,name),false);
}
});
}
@Override
public void onDeviceDisconnected() {
this.deviceName = null;
//inform the UI
runOnUiThread(new Runnable() {
@Override
public void run() {
WMCConnectionStateChangedEvent stateChangedEvent = new WMCConnectionStateChangedEvent(WMCConnectionStateChangedEvent.ConnectionState.DISCONNECTED);
EventBus.getDefault().post(stateChangedEvent);
((NotificationManager) getBaseContext().getSystemService(Context.NOTIFICATION_SERVICE)).cancel(NOTIFICATION_ID);
stopSelf();
}
});
}
@Override
public void onDeviceConnectionFailed(String error) {
runOnUiThread(new Runnable() {
@Override
public void run() {
WMCConnectionStateChangedEvent stateChangedEvent = new WMCConnectionStateChangedEvent(WMCConnectionStateChangedEvent.ConnectionState.CONNECTION_ERROR);
EventBus.getDefault().post(stateChangedEvent);
stopSelf();
}
});
}
/**
* shows a notification to the user to indicate that there is an
* ongoing connection to the WMC device
* @param message the message to show
* @param autoCancel if this notification is cancelable
*/
private void showNotification(String message, boolean autoCancel){
final NotificationManager notificationManager = ((NotificationManager) getBaseContext().getSystemService(Context.NOTIFICATION_SERVICE));
NotificationCompat.Builder builder = new NotificationCompat.Builder(getBaseContext())
.setContentTitle(getString(R.string.app_name))
.setAutoCancel(autoCancel)
.setOngoing(!autoCancel)
.setContentText(message)
.setSmallIcon(R.drawable.ic_launcher);
notificationManager.notify(NOTIFICATION_ID, builder.build());
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void runOnUiThread(Runnable runnable) {
handler.post(runnable);
}
}