package edu.fsu.cs.contextprovider.monitor;
import java.util.Timer;
import java.util.TimerTask;
import net.smart_entity.EntityManager;
import android.content.Context;
import android.content.Intent;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.widget.Toast;
import edu.fsu.cs.contextprovider.ContextExpandableListActivity;
import edu.fsu.cs.contextprovider.sensor.AccelerometerService;
import edu.fsu.cs.contextprovider.sensor.GPSService;
/**
* The structure of this class allows for only 1 Movement object to be created. Because of this the Start() and Stop()
* will stop the "Global" movement (movementObj).
* @author Meyers
*
*/
public class MovementMonitor extends TimerTask {
private static final String TAG = "MovementMonitor";
private static final boolean DEBUG = false;
private static final boolean DEBUG_TTS = false;
private static final float METERS_PER_SECOND_TO_MPH = (float)0.44704;
private static double latitude;
private static double longitude;
private static float speed;
private static Timer timer = new Timer();
private static MovementMonitor movementObj = new MovementMonitor();
private static boolean running = false;
EntityManager entityManager;
private static MovementState currentMovementState = MovementState.STILL;
public enum MovementState {
STILL (0, 0, 1001),
WALKING ((float)0.5, 2, 1000),
WALKING_ALMOST_RUNNING (3, 4, 700),
RUNNING (5, 10, 500),
RUNNING_ALMOST_DRIVING (11, 15, 100),
DRIVING (16, 200, 0);
private final float min;
private final float max;
private final long stride_time;
MovementState(float min, float max, long stride_time) {
this.min = min*METERS_PER_SECOND_TO_MPH;
this.max = max*METERS_PER_SECOND_TO_MPH;
this.stride_time = stride_time;
}
public boolean isInside(float val) {
if (val >= min && val <= max) {
return true;
}
return false;
}
public String toString() {
return this.name();
}
}
/**
* Create a timer/thread to continuous run and keep the getMovement() state up to date
*
* @param interval rate at which to run the thread, in seconds
*/
public static void StartThread(int interval) {
if (running == true) {
return;
}
if (DEBUG == true) {
Log.i(TAG, "Start()");
}
timer.schedule(movementObj, 100, interval*1000);
running = true;
}
/**
* Stop the thread/timer that keeps the movement state up to date
*/
public static void StopThread() {
if (DEBUG == true) {
Log.i(TAG, "Stop()");
}
timer.purge();
movementObj = new MovementMonitor();
running = false;
}
public static String getMovementState() {
return currentMovementState.toString();
}
public static float getSpeedMph() {
return GPSService.getSpeed()*METERS_PER_SECOND_TO_MPH;
}
@Override
public void run() {
if (GPSService.isReliable() == true) {
currentMovementState = determineMovementStateFromGps();
if (DEBUG == true) {
Log.i(TAG, "GPS determined state: " + currentMovementState);
}
if (DEBUG_TTS == true) {
ContextExpandableListActivity.tts.speak("GPS Movement " + currentMovementState, TextToSpeech.QUEUE_FLUSH, null);
}
// Use the accelerometer
} else {
currentMovementState = determineMovementStateFromAccelerometer();
if (DEBUG == true) {
Log.i(TAG, "Accelerometer determined state: " + currentMovementState);
}
if (DEBUG_TTS == true) {
ContextExpandableListActivity.tts.speak("Accelerometer Movement " + currentMovementState, TextToSpeech.QUEUE_FLUSH, null);
}
}
}
/**
* Pulls the speed from the GPS to determine the users movement state.
* If unknown then assume STILL
* @return new movement state based on speed
*/
private MovementState determineMovementStateFromGps() {
MovementState newState = MovementState.STILL;
latitude = GPSService.getLatitude();
longitude = GPSService.getLongitude();
speed = GPSService.getSpeed();
for (MovementState s : MovementState.values()) {
if (s.isInside(speed) == true) {
newState = s;
if (DEBUG == true) {
Log.i(TAG, "Changed movement state to: [" + currentMovementState + "]");
}
break;
}
}
if (DEBUG == true) {
Log.i(TAG, "GPS location (" + latitude + ", " + longitude + ") | Speed: [" + speed + "]");
}
return newState;
}
private MovementState determineMovementStateFromAccelerometer() {
MovementState newState = MovementState.STILL;
long currentTime = System.currentTimeMillis();
long stepTime = AccelerometerService.getStepTimestamp();
long sinceStepTime = currentTime - stepTime;
long diffCurrentStrideTime = 0, diffConsiderStrideTime = 0;
if (DEBUG == true) {
Log.i(TAG, "Time since last step: " + sinceStepTime + " | CurrentTime: " + currentTime + " | StepTime: " + stepTime);
}
/* Find the state that has the closest stride time */
for (MovementState s : MovementState.values()) {
diffCurrentStrideTime = Math.abs(newState.stride_time - sinceStepTime);
diffConsiderStrideTime = Math.abs(s.stride_time - sinceStepTime);
if (DEBUG == true) {
Log.i(TAG, "Considering: [" + diffConsiderStrideTime + "] | Current: [" + diffCurrentStrideTime + "]");
}
if (diffConsiderStrideTime < diffCurrentStrideTime) {
newState = s;
}
}
return newState;
}
}