[CB-463] rewrite of accel plugin

This commit is contained in:
Fil Maj 2012-05-14 13:00:11 -07:00
parent 0850229c9f
commit 71e47aa772

View File

@ -18,7 +18,11 @@
*/ */
package org.apache.cordova; package org.apache.cordova;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import org.apache.cordova.api.CordovaInterface; import org.apache.cordova.api.CordovaInterface;
import org.apache.cordova.api.Plugin; import org.apache.cordova.api.Plugin;
@ -32,6 +36,8 @@ import android.hardware.Sensor;
import android.hardware.SensorEvent; import android.hardware.SensorEvent;
import android.hardware.SensorEventListener; import android.hardware.SensorEventListener;
import android.hardware.SensorManager; import android.hardware.SensorManager;
import android.location.Location;
import android.util.Log;
import android.content.Context; import android.content.Context;
/** /**
@ -40,20 +46,20 @@ import android.content.Context;
*/ */
public class AccelListener extends Plugin implements SensorEventListener { public class AccelListener extends Plugin implements SensorEventListener {
public static int STOPPED = 0; public static int STOPPED = 0;
public static int STARTING = 1; public static int STARTING = 1;
public static int RUNNING = 2; public static int RUNNING = 2;
public static int ERROR_FAILED_TO_START = 3; public static int ERROR_FAILED_TO_START = 3;
public float TIMEOUT = 30000; // Timeout in msec to shut off listener private float x,y,z; // most recent acceleration values
private long timestamp; // time of most recent value
private int status; // status of listener
float x,y,z; // most recent acceleration values private SensorManager sensorManager; // Sensor manager
long timestamp; // time of most recent value private Sensor mSensor; // Acceleration sensor returned by sensor manager
int status; // status of listener
long lastAccessTime; // time the value was last retrieved
private SensorManager sensorManager;// Sensor manager private HashMap<String, String> watches = new HashMap<String, String>();
Sensor mSensor; // Acceleration sensor returned by sensor manager private List<String> callbacks = new ArrayList<String>();
/** /**
* Create an accelerometer listener. * Create an accelerometer listener.
@ -66,169 +72,149 @@ public class AccelListener extends Plugin implements SensorEventListener {
this.setStatus(AccelListener.STOPPED); this.setStatus(AccelListener.STOPPED);
} }
/** /**
* Sets the context of the Command. This can then be used to do things like * Sets the context of the Command. This can then be used to do things like
* get file paths associated with the Activity. * get file paths associated with the Activity.
* *
* @param ctx The context of the main Activity. * @param ctx The context of the main Activity.
*/ */
public void setContext(CordovaInterface ctx) { public void setContext(CordovaInterface ctx) {
super.setContext(ctx); super.setContext(ctx);
this.sensorManager = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE); this.sensorManager = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE);
} }
/** /**
* Executes the request and returns PluginResult. * Executes the request and returns PluginResult.
* *
* @param action The action to execute. * @param action The action to execute.
* @param args JSONArry of arguments for the plugin. * @param args JSONArry of arguments for the plugin.
* @param callbackId The callback id used when calling back into JavaScript. * @param callbackId The callback id used when calling back into JavaScript.
* @return A PluginResult object with a status and message. * @return A PluginResult object with a status and message.
*/ */
public PluginResult execute(String action, JSONArray args, String callbackId) { public PluginResult execute(String action, JSONArray args, String callbackId) {
PluginResult.Status status = PluginResult.Status.OK; PluginResult.Status status = PluginResult.Status.NO_RESULT;
String result = ""; String message = "";
PluginResult result = new PluginResult(status, message);
result.setKeepCallback(true);
try {
if (action.equals("getAcceleration")) {
if (this.status != AccelListener.RUNNING) {
// If not running, then this is an async call, so don't worry about waiting
// We drop the callback onto our stack, call start, and let start and the sensor callback fire off the callback down the road
this.callbacks.add(callbackId);
this.start();
} else {
return new PluginResult(PluginResult.Status.OK, this.getAccelerationJSON());
}
}
else if (action.equals("addWatch")) {
String watchId = args.getString(0);
this.watches.put(watchId, callbackId);
if (this.status != AccelListener.RUNNING) {
this.start();
}
}
else if (action.equals("clearWatch")) {
String watchId = args.getString(0);
if (this.watches.containsKey(watchId)) {
this.watches.remove(watchId);
if (this.size() == 0) {
this.stop();
}
}
return new PluginResult(PluginResult.Status.OK);
} else {
// Unsupported action
return new PluginResult(PluginResult.Status.INVALID_ACTION);
}
} catch (JSONException e) {
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
}
return result;
}
try { /**
if (action.equals("getStatus")) { * Identifies if action to be executed returns a value and should be run synchronously.
int i = this.getStatus(); *
return new PluginResult(status, i); * @param action The action to execute
} * @return T=returns value
else if (action.equals("start")) { */
int i = this.start(); public boolean isSynch(String action) {
return new PluginResult(status, i); if (action.equals("getAcceleration") && this.status == AccelListener.RUNNING) {
} return true;
else if (action.equals("stop")) { } else if (action.equals("addWatch") && this.status == AccelListener.RUNNING) {
this.stop(); return true;
return new PluginResult(status, 0); } else if (action.equals("clearWatch")) {
} return true;
else if (action.equals("getAcceleration")) { }
// If not running, then this is an async call, so don't worry about waiting return false;
if (this.status != AccelListener.RUNNING) { }
int r = this.start();
if (r == AccelListener.ERROR_FAILED_TO_START) {
return new PluginResult(PluginResult.Status.IO_EXCEPTION, AccelListener.ERROR_FAILED_TO_START);
}
// Wait until running
long timeout = 2000;
while ((this.status == STARTING) && (timeout > 0)) {
timeout = timeout - 100;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (timeout == 0) {
return new PluginResult(PluginResult.Status.IO_EXCEPTION, AccelListener.ERROR_FAILED_TO_START);
}
}
this.lastAccessTime = System.currentTimeMillis();
JSONObject r = new JSONObject();
r.put("x", this.x);
r.put("y", this.y);
r.put("z", this.z);
// TODO: Should timestamp be sent?
r.put("timestamp", this.timestamp);
return new PluginResult(status, r);
}
else if (action.equals("setTimeout")) {
try {
float timeout = Float.parseFloat(args.getString(0));
this.setTimeout(timeout);
return new PluginResult(status, 0);
} catch (NumberFormatException e) {
status = PluginResult.Status.INVALID_ACTION;
e.printStackTrace();
} catch (JSONException e) {
status = PluginResult.Status.JSON_EXCEPTION;
e.printStackTrace();
}
}
else if (action.equals("getTimeout")) {
float f = this.getTimeout();
return new PluginResult(status, f);
} else {
// Unsupported action
return new PluginResult(PluginResult.Status.INVALID_ACTION);
}
return new PluginResult(status, result);
} catch (JSONException e) {
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
}
}
/**
* Identifies if action to be executed returns a value and should be run synchronously.
*
* @param action The action to execute
* @return T=returns value
*/
public boolean isSynch(String action) {
if (action.equals("getStatus")) {
return true;
}
else if (action.equals("getAcceleration")) {
// Can only return value if RUNNING
if (this.status == AccelListener.RUNNING) {
return true;
}
}
else if (action.equals("getTimeout")) {
return true;
}
return false;
}
/** /**
* Called by AccelBroker when listener is to be shut down. * Called by AccelBroker when listener is to be shut down.
* Stop listener. * Stop listener.
*/ */
public void onDestroy() { public void onDestroy() {
this.stop(); this.stop();
} }
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// LOCAL METHODS // LOCAL METHODS
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
private int size() {
return this.watches.size() + this.callbacks.size();
}
/** /**
* Start listening for acceleration sensor. * Start listening for acceleration sensor.
* *
* @return status of listener * @return status of listener
*/ */
public int start() { private int start() {
// If already starting or running, then just return
if ((this.status == AccelListener.RUNNING) || (this.status == AccelListener.STARTING)) {
return this.status;
}
// If already starting or running, then just return this.setStatus(AccelListener.STARTING);
if ((this.status == AccelListener.RUNNING) || (this.status == AccelListener.STARTING)) {
return this.status;
}
// Get accelerometer from sensor manager // Get accelerometer from sensor manager
List<Sensor> list = this.sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER); List<Sensor> list = this.sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
// If found, then register as listener // If found, then register as listener
if ((list != null) && (list.size() > 0)) { if ((list != null) && (list.size() > 0)) {
this.mSensor = list.get(0); this.mSensor = list.get(0);
this.sensorManager.registerListener(this, this.mSensor, SensorManager.SENSOR_DELAY_FASTEST); this.sensorManager.registerListener(this, this.mSensor, SensorManager.SENSOR_DELAY_FASTEST);
this.setStatus(AccelListener.STARTING); this.setStatus(AccelListener.STARTING);
this.lastAccessTime = System.currentTimeMillis(); } else {
} this.setStatus(AccelListener.ERROR_FAILED_TO_START);
this.fail(AccelListener.ERROR_FAILED_TO_START, "No sensors found to register accelerometer listening to.");
return this.status;
}
// If error, then set status to error // Wait until running
else { long timeout = 2000;
this.setStatus(AccelListener.ERROR_FAILED_TO_START); while ((this.status == STARTING) && (timeout > 0)) {
} timeout = timeout - 100;
try {
return this.status; Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (timeout == 0) {
this.setStatus(AccelListener.ERROR_FAILED_TO_START);
this.fail(AccelListener.ERROR_FAILED_TO_START, "Accelerometer could not be started.");
}
return this.status;
} }
/** /**
* Stop listening to acceleration sensor. * Stop listening to acceleration sensor.
*/ */
public void stop() { private void stop() {
if (this.status != AccelListener.STOPPED) { if (this.status != AccelListener.STOPPED) {
this.sensorManager.unregisterListener(this); this.sensorManager.unregisterListener(this);
} }
this.setStatus(AccelListener.STOPPED); this.setStatus(AccelListener.STOPPED);
} }
@ -248,64 +234,92 @@ public class AccelListener extends Plugin implements SensorEventListener {
* @param SensorEvent event * @param SensorEvent event
*/ */
public void onSensorChanged(SensorEvent event) { public void onSensorChanged(SensorEvent event) {
// Only look at accelerometer events
// Only look at accelerometer events
if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER) { if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER) {
return; return;
} }
// If not running, then just return // If not running, then just return
if (this.status == AccelListener.STOPPED) { if (this.status == AccelListener.STOPPED) {
return; return;
} }
this.setStatus(AccelListener.RUNNING);
// Save time that event was received // Save time that event was received
this.timestamp = System.currentTimeMillis(); this.timestamp = System.currentTimeMillis();
this.x = event.values[0]; this.x = event.values[0];
this.y = event.values[1]; this.y = event.values[1];
this.z = event.values[2]; this.z = event.values[2];
this.setStatus(AccelListener.RUNNING); this.win();
// If values haven't been read for TIMEOUT time, then turn off accelerometer sensor to save power if (this.size() == 0) {
if ((this.timestamp - this.lastAccessTime) > this.TIMEOUT) { this.stop();
this.stop(); }
}
} }
/** private void fail(int code, String message) {
* Get status of accelerometer sensor. // Error object
* JSONObject errorObj = new JSONObject();
* @return status try {
*/ errorObj.put("code", code);
public int getStatus() { errorObj.put("message", message);
return this.status; } catch (JSONException e) {
} // TODO Auto-generated catch block
e.printStackTrace();
}
PluginResult err = new PluginResult(PluginResult.Status.ERROR, errorObj);
/** for (String callbackId: this.callbacks)
* Set the timeout to turn off accelerometer sensor if getX() hasn't been called. {
* this.error(err, callbackId);
* @param timeout Timeout in msec. }
*/ this.callbacks.clear();
public void setTimeout(float timeout) {
this.TIMEOUT = timeout;
}
/** err.setKeepCallback(true);
* Get the timeout to turn off accelerometer sensor if getX() hasn't been called.
* Iterator it = this.watches.entrySet().iterator();
* @return timeout in msec while (it.hasNext()) {
*/ Map.Entry pairs = (Map.Entry)it.next();
public float getTimeout() { this.error(err, (String)pairs.getValue());
return this.TIMEOUT; }
} }
private void win() {
// Success return object
PluginResult result = new PluginResult(PluginResult.Status.OK, this.getAccelerationJSON());
for (String callbackId: this.callbacks)
{
this.success(result, callbackId);
}
this.callbacks.clear();
result.setKeepCallback(true);
Iterator it = this.watches.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pairs = (Map.Entry)it.next();
this.success(result, (String)pairs.getValue());
}
}
/**
* Set the status and send it to JavaScript.
* @param status
*/
private void setStatus(int status) { private void setStatus(int status) {
this.status = status; this.status = status;
} }
private JSONObject getAccelerationJSON() {
JSONObject r = new JSONObject();
try {
r.put("x", this.x);
r.put("y", this.y);
r.put("z", this.z);
r.put("timestamp", this.timestamp);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return r;
}
} }