/*
* PhoneGap is available under *either* the terms of the modified BSD license *or* the
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
* Copyright (c) 2005-2011, Nitobi Software Inc.
* Copyright (c) 2011, Microsoft Corporation
* Copyright (c) 2011, Sergey Grebnov.
* Copyright (c) 2011, Jesse MacFadyen.
*/
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Threading;
using Microsoft.Devices.Sensors;
namespace WP7GapClassLib.PhoneGap.Commands
{
///
/// Captures device motion in the x, y, and z direction.
///
public class Accelerometer : BaseCommand
{
#region AccelerometerOptions class
///
/// Represents Accelerometer options.
///
[DataContract]
public class AccelerometerOptions
{
///
/// How often to retrieve the Acceleration in milliseconds
///
[DataMember(IsRequired = false, Name = "frequency")]
public int Frequency { get; set; }
///
/// Watcher id
///
[DataMember(IsRequired = false, Name = "id")]
public string Id { get; set; }
///
/// Creates options object with default parameters
///
public AccelerometerOptions()
{
this.SetDefaultValues(new StreamingContext());
}
///
/// Initializes default values for class fields.
/// Implemented in separate method because default constructor is not invoked during deserialization.
///
///
[OnDeserializing()]
public void SetDefaultValues(StreamingContext context)
{
this.Frequency = 10000;
}
}
#endregion
#region Status codes
public const int Stopped = 0;
public const int Starting = 1;
public const int Running = 2;
public const int ErrorFailedToStart = 3;
#endregion
#region Static members
///
/// Status of listener
///
private static int currentStatus;
///
/// Id for get getAcceleration method
///
private static string getAccelId = "getAccelId";
///
/// Accelerometer
///
private static Microsoft.Devices.Sensors.Accelerometer accelerometer = new Microsoft.Devices.Sensors.Accelerometer();
///
/// Listeners for callbacks
///
private static Dictionary watchers = new Dictionary();
#endregion
///
/// Time the value was last changed
///
private DateTime lastValueChangedTime;
///
/// Accelerometer options
///
private AccelerometerOptions accelOptions;
///
/// Start listening for acceleration sensor
///
public void startWatch(string options)
{
try
{
accelOptions = JSON.JsonHelper.Deserialize(options);
}
catch (Exception ex)
{
this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, ex.Message));
return;
}
if (string.IsNullOrEmpty(accelOptions.Id))
{
this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
return;
}
try
{
lock (accelerometer)
{
watchers.Add(accelOptions.Id, this);
accelerometer.CurrentValueChanged += watchers[accelOptions.Id].accelerometer_CurrentValueChanged;
accelerometer.Start();
this.SetStatus(Starting);
}
}
catch (Exception e)
{
this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, ErrorFailedToStart));
return;
}
}
///
/// Stops listening to acceleration sensor
///
public void stopWatch(string options)
{
try
{
accelOptions = JSON.JsonHelper.Deserialize(options);
}
catch (Exception ex)
{
this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, ex.Message));
return;
}
if (string.IsNullOrEmpty(accelOptions.Id))
{
this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
return;
}
if (currentStatus != Stopped)
{
lock (accelerometer)
{
Accelerometer watcher = watchers[accelOptions.Id];
watcher.Dispose();
accelerometer.CurrentValueChanged -= watcher.accelerometer_CurrentValueChanged;
watchers.Remove(accelOptions.Id);
}
}
this.SetStatus(Stopped);
this.DispatchCommandResult();
}
///
/// Gets current accelerometer coordinates
///
public void getAcceleration(string options)
{
try
{
if (currentStatus != Running)
{
int status = this.start();
if (status == ErrorFailedToStart)
{
DispatchCommandResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, ErrorFailedToStart));
return;
}
long timeout = 2000;
while ((currentStatus == Starting) && (timeout > 0))
{
timeout = timeout - 100;
Thread.Sleep(100);
}
if (currentStatus != Running)
{
DispatchCommandResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, ErrorFailedToStart));
return;
}
}
lock (accelerometer)
{
if (watchers.ContainsKey(getAccelId))
{
accelerometer.CurrentValueChanged -= watchers[getAccelId].accelerometer_CurrentValueChanged;
watchers.Remove(getAccelId);
}
DispatchCommandResult(new PluginResult(PluginResult.Status.OK, GetCurrentAccelerationFormatted()));
}
}
catch (UnauthorizedAccessException e)
{
DispatchCommandResult(new PluginResult(PluginResult.Status.ILLEGAL_ACCESS_EXCEPTION, ErrorFailedToStart));
}
catch (Exception e)
{
DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, ErrorFailedToStart));
}
}
///
/// Sensor listener event
///
private void accelerometer_CurrentValueChanged(object sender, SensorReadingEventArgs e)
{
this.SetStatus(Running);
if (accelOptions != null)
{
if (((DateTime.Now - lastValueChangedTime).TotalMilliseconds) > accelOptions.Frequency)
{
lastValueChangedTime = DateTime.Now;
PluginResult result = new PluginResult(PluginResult.Status.OK, GetCurrentAccelerationFormatted());
result.KeepCallback = true;
DispatchCommandResult(result);
}
}
if (watchers.Count == 0)
{
accelerometer.Stop();
this.SetStatus(Stopped);
}
}
///
/// Starts listening for acceleration sensor
///
/// status of listener
private int start()
{
if ((currentStatus == Running) || (currentStatus == Starting))
{
return currentStatus;
}
try
{
lock (accelerometer)
{
watchers.Add(getAccelId, this);
accelerometer.CurrentValueChanged += watchers[getAccelId].accelerometer_CurrentValueChanged;
accelerometer.Start();
this.SetStatus(Starting);
}
}
catch (Exception e)
{
this.SetStatus(ErrorFailedToStart);
}
return currentStatus;
}
///
/// Formats current coordinates into JSON format
///
/// Coordinates in JSON format
private string GetCurrentAccelerationFormatted()
{
string resultCoordinates = String.Format("\"x\":{0},\"y\":{1},\"z\":{2}",
accelerometer.CurrentValue.Acceleration.X.ToString("0.00000"),
accelerometer.CurrentValue.Acceleration.Y.ToString("0.00000"),
accelerometer.CurrentValue.Acceleration.Z.ToString("0.00000"));
resultCoordinates = "{" + resultCoordinates + "}";
return resultCoordinates;
}
///
/// Sets current status
///
/// current status
private void SetStatus(int status)
{
currentStatus = status;
}
}
}