Fix for Issue #228: Align Compass support with iOS

This commit is contained in:
macdonst 2011-09-28 17:35:50 -04:00
parent 336a58ca5a
commit 821eb24a54
2 changed files with 228 additions and 181 deletions

View File

@ -9,6 +9,21 @@
if (!PhoneGap.hasResource("compass")) { if (!PhoneGap.hasResource("compass")) {
PhoneGap.addResource("compass"); PhoneGap.addResource("compass");
CompassError = function(){
this.code = null;
};
// Capture error codes
CompassError.COMPASS_INTERNAL_ERR = 0;
CompassError.COMPASS_NOT_SUPPORTED = 20;
CompassHeading = function() {
this.magneticHeading = null;
this.trueHeading = null;
this.headingAccuracy = null;
this.timestamp = null;
};
/** /**
* This class provides access to device Compass data. * This class provides access to device Compass data.
* @constructor * @constructor
@ -111,6 +126,14 @@ Compass.prototype.clearWatch = function(id) {
} }
}; };
Compass.prototype._castDate = function(pluginResult) {
if (pluginResult.message.timestamp) {
var timestamp = new Date(pluginResult.message.timestamp);
pluginResult.message.timestamp = timestamp;
}
return pluginResult;
};
PhoneGap.addConstructor(function() { PhoneGap.addConstructor(function() {
if (typeof navigator.compass === "undefined") { if (typeof navigator.compass === "undefined") {
navigator.compass = new Compass(); navigator.compass = new Compass();

View File

@ -11,6 +11,7 @@ import java.util.List;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject;
import com.phonegap.api.PhonegapActivity; import com.phonegap.api.PhonegapActivity;
import com.phonegap.api.Plugin; import com.phonegap.api.Plugin;
@ -27,129 +28,130 @@ import android.content.Context;
*/ */
public class CompassListener extends Plugin implements SensorEventListener { public class CompassListener 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 long TIMEOUT = 30000; // Timeout in msec to shut off listener public long TIMEOUT = 30000; // Timeout in msec to shut off listener
int status; // status of listener int status; // status of listener
float heading; // most recent heading value float heading; // most recent heading value
long timeStamp; // time of most recent value long timeStamp; // time of most recent value
long lastAccessTime; // time the value was last retrieved long lastAccessTime; // time the value was last retrieved
int accuracy; // accuracy of the sensor
private SensorManager sensorManager;// Sensor manager private SensorManager sensorManager;// Sensor manager
Sensor mSensor; // Compass sensor returned by sensor manager Sensor mSensor; // Compass sensor returned by sensor manager
/** /**
* Constructor. * Constructor.
*/ */
public CompassListener() { public CompassListener() {
this.timeStamp = 0; this.timeStamp = 0;
this.setStatus(CompassListener.STOPPED); this.setStatus(CompassListener.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(PhonegapActivity ctx) { public void setContext(PhonegapActivity 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.OK;
String result = ""; String result = "";
try { try {
if (action.equals("start")) { if (action.equals("start")) {
this.start(); this.start();
} }
else if (action.equals("stop")) { else if (action.equals("stop")) {
this.stop(); this.stop();
} }
else if (action.equals("getStatus")) { else if (action.equals("getStatus")) {
int i = this.getStatus(); int i = this.getStatus();
return new PluginResult(status, i); return new PluginResult(status, i);
} }
else if (action.equals("getHeading")) { else if (action.equals("getHeading")) {
// If not running, then this is an async call, so don't worry about waiting // If not running, then this is an async call, so don't worry about waiting
if (this.status != RUNNING) { if (this.status != RUNNING) {
int r = this.start(); int r = this.start();
if (r == ERROR_FAILED_TO_START) { if (r == ERROR_FAILED_TO_START) {
return new PluginResult(PluginResult.Status.IO_EXCEPTION, ERROR_FAILED_TO_START); return new PluginResult(PluginResult.Status.IO_EXCEPTION, ERROR_FAILED_TO_START);
} }
// Wait until running // Wait until running
long timeout = 2000; long timeout = 2000;
while ((this.status == STARTING) && (timeout > 0)) { while ((this.status == STARTING) && (timeout > 0)) {
timeout = timeout - 100; timeout = timeout - 100;
try { try {
Thread.sleep(100); Thread.sleep(100);
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
if (timeout == 0) { if (timeout == 0) {
return new PluginResult(PluginResult.Status.IO_EXCEPTION, AccelListener.ERROR_FAILED_TO_START); return new PluginResult(PluginResult.Status.IO_EXCEPTION, AccelListener.ERROR_FAILED_TO_START);
} }
} }
float f = this.getHeading(); //float f = this.getHeading();
return new PluginResult(status, f); return new PluginResult(status, getCompassHeading(), "navigator.compass._castDate");
} }
else if (action.equals("setTimeout")) { else if (action.equals("setTimeout")) {
this.setTimeout(args.getLong(0)); this.setTimeout(args.getLong(0));
} }
else if (action.equals("getTimeout")) { else if (action.equals("getTimeout")) {
long l = this.getTimeout(); long l = this.getTimeout();
return new PluginResult(status, l); return new PluginResult(status, l);
} }
return new PluginResult(status, result); return new PluginResult(status, result);
} catch (JSONException e) { } catch (JSONException e) {
e.printStackTrace(); e.printStackTrace();
return new PluginResult(PluginResult.Status.JSON_EXCEPTION); return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
} }
} }
/** /**
* Identifies if action to be executed returns a value and should be run synchronously. * Identifies if action to be executed returns a value and should be run synchronously.
* *
* @param action The action to execute * @param action The action to execute
* @return T=returns value * @return T=returns value
*/ */
public boolean isSynch(String action) { public boolean isSynch(String action) {
if (action.equals("getStatus")) { if (action.equals("getStatus")) {
return true; return true;
} }
else if (action.equals("getHeading")) { else if (action.equals("getHeading")) {
// Can only return value if RUNNING // Can only return value if RUNNING
if (this.status == RUNNING) { if (this.status == RUNNING) {
return true; return true;
} }
} }
else if (action.equals("getTimeout")) { else if (action.equals("getTimeout")) {
return true; return true;
} }
return false; return false;
} }
/** /**
* Called when listener is to be shut down and object is being destroyed. * Called when listener is to be shut down and object is being destroyed.
*/ */
public void onDestroy() { public void onDestroy() {
this.stop(); this.stop();
} }
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// LOCAL METHODS // LOCAL METHODS
@ -158,113 +160,135 @@ public class CompassListener extends Plugin implements SensorEventListener {
/** /**
* Start listening for compass sensor. * Start listening for compass sensor.
* *
* @return status of listener * @return status of listener
*/ */
public int start() { public int start() {
// If already starting or running, then just return // If already starting or running, then just return
if ((this.status == CompassListener.RUNNING) || (this.status == CompassListener.STARTING)) { if ((this.status == CompassListener.RUNNING) || (this.status == CompassListener.STARTING)) {
return this.status; return this.status;
} }
// Get accelerometer from sensor manager // Get accelerometer from sensor manager
List<Sensor> list = this.sensorManager.getSensorList(Sensor.TYPE_ORIENTATION); List<Sensor> list = this.sensorManager.getSensorList(Sensor.TYPE_ORIENTATION);
// If found, then register as listener // If found, then register as listener
if (list.size() > 0) { if (list.size() > 0) {
this.mSensor = list.get(0); this.mSensor = list.get(0);
this.sensorManager.registerListener(this, this.mSensor, SensorManager.SENSOR_DELAY_NORMAL); this.sensorManager.registerListener(this, this.mSensor, SensorManager.SENSOR_DELAY_NORMAL);
this.lastAccessTime = System.currentTimeMillis(); this.lastAccessTime = System.currentTimeMillis();
this.setStatus(CompassListener.STARTING); this.setStatus(CompassListener.STARTING);
} }
// If error, then set status to error // If error, then set status to error
else { else {
this.setStatus(CompassListener.ERROR_FAILED_TO_START); this.setStatus(CompassListener.ERROR_FAILED_TO_START);
} }
return this.status; return this.status;
} }
/** /**
* Stop listening to compass sensor. * Stop listening to compass sensor.
*/ */
public void stop() { public void stop() {
if (this.status != CompassListener.STOPPED) { if (this.status != CompassListener.STOPPED) {
this.sensorManager.unregisterListener(this); this.sensorManager.unregisterListener(this);
} }
this.setStatus(CompassListener.STOPPED); this.setStatus(CompassListener.STOPPED);
} }
public void onAccuracyChanged(Sensor sensor, int accuracy) { public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
} }
/** /**
* Sensor listener event. * Sensor listener event.
* *
* @param SensorEvent event * @param SensorEvent event
*/ */
public void onSensorChanged(SensorEvent event) { public void onSensorChanged(SensorEvent event) {
// We only care about the orientation as far as it refers to Magnetic North // We only care about the orientation as far as it refers to Magnetic North
float heading = event.values[0]; float heading = event.values[0];
// Save heading // Save heading
this.timeStamp = System.currentTimeMillis(); this.timeStamp = System.currentTimeMillis();
this.heading = heading; this.heading = heading;
this.setStatus(CompassListener.RUNNING); this.setStatus(CompassListener.RUNNING);
// If heading hasn't been read for TIMEOUT time, then turn off compass sensor to save power // If heading hasn't been read for TIMEOUT time, then turn off compass sensor to save power
if ((this.timeStamp - this.lastAccessTime) > this.TIMEOUT) { if ((this.timeStamp - this.lastAccessTime) > this.TIMEOUT) {
this.stop(); this.stop();
} }
} }
/** /**
* Get status of compass sensor. * Get status of compass sensor.
* *
* @return status * @return status
*/ */
public int getStatus() { public int getStatus() {
return this.status; return this.status;
} }
/** /**
* Get the most recent compass heading. * Get the most recent compass heading.
* *
* @return heading * @return heading
*/ */
public float getHeading() { public float getHeading() {
this.lastAccessTime = System.currentTimeMillis(); this.lastAccessTime = System.currentTimeMillis();
return this.heading; return this.heading;
} }
/** /**
* Set the timeout to turn off compass sensor if getHeading() hasn't been called. * Set the timeout to turn off compass sensor if getHeading() hasn't been called.
* *
* @param timeout Timeout in msec. * @param timeout Timeout in msec.
*/ */
public void setTimeout(long timeout) { public void setTimeout(long timeout) {
this.TIMEOUT = timeout; this.TIMEOUT = timeout;
} }
/** /**
* Get the timeout to turn off compass sensor if getHeading() hasn't been called. * Get the timeout to turn off compass sensor if getHeading() hasn't been called.
* *
* @return timeout in msec * @return timeout in msec
*/ */
public long getTimeout() { public long getTimeout() {
return this.TIMEOUT; return this.TIMEOUT;
} }
/** /**
* Set the status and send it to JavaScript. * Set the status and send it to JavaScript.
* @param status * @param status
*/ */
private void setStatus(int status) { private void setStatus(int status) {
this.status = status; this.status = status;
} }
/**
* Create the CompassHeading JSON object to be returned to JavaScript
*
* @return a compass heading
*/
private JSONObject getCompassHeading() {
JSONObject obj = new JSONObject();
try {
obj.put("magneticHeading", this.getHeading());
obj.put("trueHeading", this.getHeading());
// Since the magnetic and true heading are always the same our and accuracy
// is defined as the difference between true and magnetic always return zero
obj.put("headingAccuracy", 0);
obj.put("timestamp", this.timeStamp);
} catch (JSONException e) {
// Should never happen
}
return obj;
}
} }