/**
* Funf: Open Sensing Framework
* Copyright (C) 2010-2011 Nadav Aharony, Wei Pan, Alex Pentland.
* Acknowledgments: Alan Gardner
* Contact: nadav@media.mit.edu
*
* This file is part of Funf.
*
* Funf is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* Funf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Funf. If not, see <http://www.gnu.org/licenses/>.
*/
package edu.mit.media.funf.probe;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import edu.mit.media.funf.Utils;
public abstract class SensorProbe extends Probe {
private SensorManager sensorManager;
private Sensor sensor;
private SensorEventListener sensorListener;
private BlockingQueue<SensorEventCopy> recentEvents;
private Timer senderTimer;
private Handler handler;
private Runnable sendDataRunnable = new Runnable() {
@Override
public void run() {
sendProbeData();
if (handler != null) {
handler.postDelayed(this, 1000L);
}
}
};
protected SensorManager getSensorManager() {
if (sensorManager == null) {
sensorManager = (SensorManager) this.getSystemService(Context.SENSOR_SERVICE);
}
return sensorManager;
}
@Override
public Parameter[] getAvailableParameters() {
return new Parameter[] {
new Parameter(Parameter.Builtin.DURATION, getDefaultDuration()),
new Parameter(Parameter.Builtin.PERIOD, getDefaultPeriod()),
new Parameter(Parameter.Builtin.START, 0L),
new Parameter(Parameter.Builtin.END, 0L)
};
}
protected long getDefaultPeriod() {
return 1800L;
}
protected long getDefaultDuration() {
return 60;
}
@Override
public String[] getRequiredPermissions() {
return new String[]{};
}
@Override
public boolean isAvailableOnDevice() {
return getSensorManager().getDefaultSensor(getSensorType()) != null;
}
@Override
protected void onEnable() {
handler = new Handler();
sensor = getSensorManager().getDefaultSensor(getSensorType());
recentEvents = new LinkedBlockingQueue<SensorEventCopy>();
sensorListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
// TODO: the same event objects are reused
recentEvents.offer(new SensorEventCopy(event));
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
};
}
@Override
protected void onDisable() {
// Nothing to do
}
@Override
public void onRun(Bundle params) {
Log.i(TAG, "SensorKeys listener:" + sensorListener + " SensorKeys:" + sensor + " SensorManager:" + getSensorManager());
getSensorManager().registerListener(sensorListener,sensor, getSensorDelay(params));
Log.i(TAG, "RecentEvents before clear:" + recentEvents.size());
recentEvents.clear();
Log.i(TAG, "Creating thread");
handler.postDelayed(sendDataRunnable, 1000L);
//senderTimer = new Timer();
//senderTimer.schedule(new TimerTask() {
// @Override
// public void run() {
// sendProbeData();
// }
//}, 1000L, 1000L);
}
@Override
public void onStop() {
if (sensor == null) {
return;
}
getSensorManager().unregisterListener(sensorListener);
handler.removeCallbacks(sendDataRunnable);
//senderTimer.cancel();
if (!recentEvents.isEmpty()) {
sendProbeData();
}
}
@Override
public void sendProbeData() {
Log.i(TAG, "RecentEvents before send:" + recentEvents.size());
if (!recentEvents.isEmpty()) {
Bundle data = new Bundle();
List<SensorEventCopy> events = new ArrayList<SensorEventCopy>();
recentEvents.drainTo(events);
if (!events.isEmpty()) {
Sensor sensor = events.get(0).sensor;
Bundle sensorBundle = new Bundle();
sensorBundle.putFloat("MAXIMUM_RANGE", sensor.getMaximumRange());
sensorBundle.putString("NAME", sensor.getName());
sensorBundle.putFloat("POWER", sensor.getPower());
sensorBundle.putFloat("RESOLUTION", sensor.getResolution());
sensorBundle.putInt("TYPE", sensor.getType());
sensorBundle.putString("VENDOR", sensor.getVendor());
sensorBundle.putInt("VERSION", sensor.getVersion());
String[] valueNames = getValueNames();
long[] timestamp = new long[events.size()];
int[] accuracy = new int[events.size()];
int valuesLength = Math.min(valueNames.length, events.get(0).values.length); // Accounts for optional values
float[][] values = new float[valuesLength][events.size()];
for (int i=0; i<events.size(); i++) {
SensorEventCopy event = events.get(i);
timestamp[i] = event.timestamp;
accuracy[i] = event.accuracy;
for (int valueIndex=0; valueIndex<valuesLength; valueIndex++) {
values[valueIndex][i] = event.values[valueIndex];
}
}
data.putBundle("SENSOR", sensorBundle);
data.putLongArray("EVENT_TIMESTAMP", timestamp);
data.putIntArray("ACCURACY", accuracy);
for (int valueIndex=0; valueIndex<valuesLength; valueIndex++) {
data.putFloatArray(valueNames[valueIndex], values[valueIndex]);
}
sendProbeData(Utils.getTimestamp(), data);
} else {
Log.i(TAG, "Recent events is empty.");
}
} else {
Log.i(TAG, "Recent events is empty.");
}
}
/**
* Local copy of sensor data to process.
* TODO: May want to resuse these objects
*/
private class SensorEventCopy {
public final long timestamp;
public final int accuracy;
public final float[] values;
public final Sensor sensor;
public SensorEventCopy(SensorEvent event) {
this.timestamp = event.timestamp;
this.accuracy = event.accuracy;
this.values = new float[event.values.length];
System.arraycopy(event.values, 0, this.values, 0, event.values.length);
this.sensor = event.sensor;
}
}
public abstract int getSensorType();
public int getSensorDelay(Bundle params) {
return SensorManager.SENSOR_DELAY_GAME;
}
public abstract String[] getValueNames();
}