package tinygsn.services;
import android.content.Context;
import android.util.Log;
import android.view.View;
import android.widget.ListView;
import android.widget.Switch;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.Map;
import tinygsn.beans.StaticData;
import tinygsn.beans.StreamElement;
import tinygsn.beans.WrapperConfig;
import tinygsn.gui.android.R;
import tinygsn.gui.android.TinyGSN;
import tinygsn.gui.android.utils.SensorRow;
import tinygsn.model.wrappers.AbstractWrapper;
import tinygsn.storage.db.SqliteStorageManager;
import tinygsn.utils.ToastUtils;
public class LocationScheduler extends AbstractScheduler {
public static final int STATE_LOST = 0;
public static final int STATE_GPS = 1;
public static final int STATE_STATIONARY = 2;
public static final int REASON_ACC = 0;
public static final int REASON_WIFI = 1;
public static final int REASON_GPS = 2;
private static final String accelerometerType = "tinygsn.model.wrappers.AndroidAccelerometerWrapper";
private static final String gpsType = "tinygsn.model.wrappers.AndroidGPSWrapper";
private static final String gyroscopeType = "tinygsn.model.wrappers.AndroidGyroscopeWrapper";
private static final String wifiType = "tinygsn.model.wrappers.WifiWrapper";
private static final String[] wrappers = new String[]{accelerometerType, gpsType, gyroscopeType, wifiType};
public final Class<? extends WrapperService> getSERVICE() {
return LocationSchedulerService.class;
}
private static SqliteStorageManager storage = new SqliteStorageManager();
public LocationScheduler(WrapperConfig wc) {
super(wc);
}
public LocationScheduler() {
}
@Override
public String[] getManagedSensors() {
return wrappers;
}
public void runOnce() {
int machineState = STATE_LOST;
int reason = REASON_ACC;
//constants:
int numLatest = 10;
double accelerometerThreshold = 1.3;
int wifiCountThreshold = 15;
int SamplingRateAccelerometerMoving = 3;
int SamplingRateAccelerometerStationary = 1;
int SamplingRateAccelerometerLost = 2;
int SamplingRateGyroscopeMoving = 3;
int SamplingRateGyroscopeStationary = 1;
int SamplingRateGyroscopeLost = 2;
int SamplingRateGPSMoving = 1;
int SamplingRateGPSStationary = 0;
int SamplingRateGPSLost = 2;
int SamplingRateWifiMoving = 0;
int SamplingRateWifiStationary = 2;
int SamplingRateWifiLost = 1;
//end of constants
AbstractWrapper accelerometerWrapper;
String accelerometerVsName = null;
AbstractWrapper gpsWrapper;
String gpsVsName = null;
AbstractWrapper wifiWrapper;
String wifiVsName = null;
int[] s = storage.getLatestState();
machineState = s[0];
reason = s[1];
try {
//get the wrappers
accelerometerWrapper = StaticData.getWrapperByName(accelerometerType);
gpsWrapper = StaticData.getWrapperByName(gpsType);
wifiWrapper = StaticData.getWrapperByName(wifiType);
//get the first attached VS
accelerometerVsName = storage.getVSfromSource(accelerometerType).get(0);
wifiVsName = storage.getVSfromSource(wifiType).get(0);
gpsVsName = storage.getVSfromSource(gpsType).get(0);
} catch (Exception e) {
// Get Switch to click on it to deactivate the LocationScheduler
ListView listViewScheduler = (ListView) TinyGSN.getCurrentActivity().findViewById(R.id.scheduler_list);
int count = listViewScheduler.getChildCount();
for (int i = 0; i < count; i++) {
View view = listViewScheduler.getChildAt(i);
ArrayList<View> views = view.getTouchables();
for (int j = 0; j < views.size(); j++) {
SensorRow sensorRow = (SensorRow) listViewScheduler.getAdapter().getItem(j);
if (sensorRow.getName().equals("tinygsn.services.LocationScheduler")) {
final Switch sw = (Switch) views.get(j);
sw.post(new Runnable() {
@Override
public void run() {
sw.performClick();
}
});
j = views.size();
i = count;
}
}
}
// Warn the user with a Toast
warnUserOfError();
return;
}
//calculation of parameters
Log.d("tinygsn-scheduler", "State is: " + machineState);
long curTime = System.currentTimeMillis();
double avgChangedAccelometer = 0;
boolean gpsConstant = true;
boolean isInKnownWifiAccess = true;
ArrayList<StreamElement> accelerometerResult = null;
ArrayList<StreamElement> gpsResult = null;
ArrayList<StreamElement> wifiResult = null;
if (wifiVsName != null) {
wifiResult = storage.executeQueryGetLatestValues("vs_" + wifiVsName, wifiWrapper.getFieldList(), wifiWrapper.getFieldType(), numLatest, curTime - 120000);
isInKnownWifiAccess = ContainsFamiliarWifis(wifiResult, wifiCountThreshold);
Log.d("tinygsn-scheduler", "is in known wifi access point: " + isInKnownWifiAccess);
}
if (gpsVsName != null) {
gpsResult = storage.executeQueryGetLatestValues("vs_" + gpsVsName, gpsWrapper.getFieldList(), gpsWrapper.getFieldType(), 180, curTime - 180000);
if (gpsResult != null && gpsResult.size() != 0) {
if (gpsResult.get(gpsResult.size() - 1).getTimeStamp() - gpsResult.get(0).getTimeStamp() > 120000) {
long longitude = Math.round(((Double) (gpsResult.get(0).getData("longitude")) * 1000));
long latitude = Math.round(((Double) (gpsResult.get(0).getData("latitude")) * 1000));
for (int i = 0; i < gpsResult.size(); i++) {
if (Math.round(((Double) (gpsResult.get(i).getData("longitude")) * 1000)) != longitude ||
Math.round(((Double) (gpsResult.get(i).getData("latitude")) * 1000)) != latitude)
gpsConstant = false;
}
} else {
gpsConstant = false;
}
} else
gpsConstant = false;
Log.d("tinygsn-scheduler", "is GPS constant: " + gpsConstant);
}
if (accelerometerVsName != null) {
accelerometerResult = storage.executeQueryGetLatestValues("vs_" + accelerometerVsName, accelerometerWrapper.getFieldList(), accelerometerWrapper.getFieldType(), 32, curTime - 30000);
if (accelerometerResult.size() > 1) {
for (int i = 1; i < accelerometerResult.size(); i++) {
double changedAccelerometer = Math.pow((Double) (accelerometerResult.get(i).getData("x")) - (Double) (accelerometerResult.get(i - 1).getData("x")), 2);
changedAccelerometer += Math.pow((Double) (accelerometerResult.get(i).getData("y")) - (Double) (accelerometerResult.get(i - 1).getData("y")), 2);
changedAccelerometer += Math.pow((Double) (accelerometerResult.get(i).getData("z")) - (Double) (accelerometerResult.get(i - 1).getData("z")), 2);
avgChangedAccelometer += Math.sqrt(changedAccelerometer);
}
avgChangedAccelometer = avgChangedAccelometer / accelerometerResult.size();
}
Log.d("tinygsn-scheduler", "average Acc change: " + avgChangedAccelometer);
}
//end of parameter calculation
//checking for next state
if (gpsResult != null && gpsResult.size() != 0) {
Log.d("tinygsn-scheduler", "Last GPS fix is : " + (curTime - gpsResult.get(0).getTimeStamp()) / 1000 + "s old.");
} else {
Log.d("tinygsn-scheduler", "no GPS results");
}
if (wifiResult != null && wifiResult.size() != 0) {
Log.d("tinygsn-scheduler", "Last wifi scan is : " + (curTime - wifiResult.get(0).getTimeStamp()) / 1000 + "s old.");
} else {
Log.d("tinygsn-scheduler", "no wifi results");
}
if (accelerometerResult != null && accelerometerResult.size() != 0) {
Log.d("tinygsn-scheduler", "Last acc scan is : " + (curTime - accelerometerResult.get(0).getTimeStamp()) / 1000 + "s old.");
} else {
Log.d("tinygsn-scheduler", "no acc results");
}
switch (machineState) {
case STATE_LOST:
storage.setWrapperInfo(gyroscopeType, 15, SamplingRateGyroscopeLost);
storage.setWrapperInfo(accelerometerType, 15, SamplingRateAccelerometerLost);
storage.setWrapperInfo(gpsType, 15, SamplingRateGPSLost);
storage.setWrapperInfo(wifiType, 60, SamplingRateWifiLost);
//changing stage
if (gpsResult != null && gpsResult.size() != 0) //gps fixed
{
machineState = STATE_GPS;
Log.d("tinygsn-scheduler", "new state GPS");
} else if (wifiResult != null && wifiResult.size() != 0 && isInKnownWifiAccess) {
machineState = STATE_STATIONARY;
reason = REASON_WIFI;
Log.d("tinygsn-scheduler", "new state STATIONARY (wifi)");
} else if (accelerometerResult != null && accelerometerResult.size() != 0 && avgChangedAccelometer < accelerometerThreshold) {
machineState = STATE_STATIONARY;
reason = REASON_ACC;
Log.d("tinygsn-scheduler", "new state STATIONARY (acc)");
}
break;
case STATE_GPS:
storage.setWrapperInfo(gyroscopeType, 15, SamplingRateGyroscopeMoving);
storage.setWrapperInfo(accelerometerType, 15, SamplingRateAccelerometerMoving);
storage.setWrapperInfo(gpsType, 15, SamplingRateGPSMoving);
storage.setWrapperInfo(wifiType, 60, SamplingRateWifiMoving);
if (gpsResult == null || gpsResult.size() == 0) //gps lost
{
machineState = STATE_LOST;
Log.d("tinygsn-scheduler", "new state LOST");
} else if (gpsResult != null && gpsResult.size() != 0 && gpsConstant) {
machineState = STATE_STATIONARY;
reason = REASON_GPS;
Log.d("tinygsn-scheduler", "new state STATIONARY (gps)");
} else if (accelerometerResult != null && accelerometerResult.size() != 0 && avgChangedAccelometer < accelerometerThreshold) {
machineState = STATE_STATIONARY;
reason = REASON_ACC;
Log.d("tinygsn-scheduler", "new state STATIONARY (acc)");
}
break;
case STATE_STATIONARY:
storage.setWrapperInfo(gyroscopeType, 15, SamplingRateGyroscopeStationary);
storage.setWrapperInfo(accelerometerType, 15, SamplingRateAccelerometerStationary);
storage.setWrapperInfo(gpsType, 15, SamplingRateGPSStationary);
storage.setWrapperInfo(wifiType, 60, SamplingRateWifiStationary);
if (reason == REASON_WIFI && (wifiResult == null || wifiResult.size() == 0 || !isInKnownWifiAccess)) {
machineState = STATE_LOST;
Log.d("tinygsn-scheduler", "new state LOST");
} else if (reason == REASON_ACC || reason == REASON_GPS) {
if (wifiResult != null && wifiResult.size() != 0 && isInKnownWifiAccess) {
reason = REASON_WIFI;
Log.d("tinygsn-scheduler", "new state STATIONARY (wifi)");
} else if (accelerometerResult != null && accelerometerResult.size() != 0 && avgChangedAccelometer > accelerometerThreshold) {
machineState = STATE_LOST;
Log.d("tinygsn-scheduler", "new state LOST");
}
}
}
storage.executeInsertSamples(machineState, reason);
return;
}
private boolean ContainsFamiliarWifis(ArrayList<StreamElement> wifiResult, int wifiCountThreshold) {
Map<Long, Integer> freqs = storage.getFrequencies();
for (int i = 0; i < wifiResult.size(); i++) {
Long k = ((Double) (wifiResult.get(i).getData("mac1"))).longValue() * 16777216 + ((Double) (wifiResult.get(i).getData("mac2"))).longValue();
if (freqs.containsKey(k) && freqs.get(k) > wifiCountThreshold) {
return true;
}
}
return false;
}
private void warnUserOfError() {
Context context = StaticData.globalContext.getApplicationContext();
CharSequence text = "The Location scheduler needs existing virtual sensors for GPS, Wifi and Accelerometer.";
int duration = Toast.LENGTH_LONG;
ToastUtils.showToastInUiThread(context, text, duration);
}
public static class LocationSchedulerService extends WrapperService {
public LocationSchedulerService() {
super("LocationScheduler");
setIntentRedelivery(true);
}
}
}