Shake that Windows Phone 7 and detect it

Alright, when you look at what apps are popular, you’ll see a lot of apps that interact with the accelerometer in a way like: Shake your phone baby!

Yes we have the accelerometer on the Windows Phone 7 as well, how to use it? That’s simple.

1: Reference the Microsoft.Devices.Sensors assembly.

Add a Add a reference to the Microsoft.Devices.Sensors assembly

2: Create an instance of the Accelerometer.

private readonly Accelerometer _sensor = new Accelerometer();

3: Start listening to the ReadingChanged

_sensor.ReadingChanged += ReadingChanged;

private void ReadingChanged(object sender, AccelerometerReadingEventArgs e)
{
}

The structure of the AccelerometerReadingEventArgs looks like this.

public class AccelerometerReadingEventArgs : EventArgs
{
    public double X { get; }
    public double Y { get; }
    public double Z { get; }
    public DateTimeOffset Timestamp { get; }
}

Pretty simple, X, Y and Z coordinates, how to read them?

image

Source: http://windowsteamblog.com/windows_phone/b/wpdev/archive/2010/09/08/using-the-accelerometer-on-windows-phone-7.aspx

Shake it

That’s about it for the basics. You can do a lot of things with the accelerometer. I want to know when the device is shaken. I started with a bit of google, and found: Shake Detection by Mark Arteaga. Nice article with a good explanation of the code. Though, he didn’t have a chance to test the code, and it was also based on a pre-release version of the Developer Tools. So after some adjustments I came with the following code that both compiles in the final Windows Phone 7 Developers Tools and also runs on the LG Prototype.

public class AccelerometerSensorWithShakeDetection : IDisposable
{
    private const double ShakeThreshold = 0.7;
    private readonly Accelerometer _sensor = new Accelerometer();
    private AccelerometerReadingEventArgs _lastReading;
    private int _shakeCount;
    private bool _shaking;

    public AccelerometerSensorWithShakeDetection()
    {
        var sensor = new Accelerometer();
        if (sensor.State == SensorState.NotSupported)
            throw new NotSupportedException("Accelerometer not supported on this device");
        _sensor = sensor;
    }

    public SensorState State
    {
        get { return _sensor.State; }
    }

    #region IDisposable Members

    public void Dispose()
    {
        if (_sensor != null)
            _sensor.Dispose();
    }

    #endregion

    private event EventHandler ShakeDetectedHandler;

    public event EventHandler ShakeDetected
    {
        add
        {
            ShakeDetectedHandler += value;
                
        }
        remove
        {
            ShakeDetectedHandler -= value;
            _sensor.ReadingChanged -= ReadingChanged;
        }
    }

    public void Start()
    {
        if (_sensor != null)
            _sensor.Start();
    }

    public void Stop()
    {
        if (_sensor != null)
            _sensor.Stop();
    }

    private void ReadingChanged(object sender, AccelerometerReadingEventArgs e)
    {
        //Code for checking shake detection
        if (_sensor.State == SensorState.Ready)
        {
            AccelerometerReadingEventArgs reading = e;
            try
            {
                if (_lastReading != null)
                {
                    if (!_shaking && CheckForShake(_lastReading, reading, ShakeThreshold) && _shakeCount >= 1)
                    {
                        //We are shaking
                        _shaking = true;
                        _shakeCount = 0;
                        OnShakeDetected();
                    }
                    else if (CheckForShake(_lastReading, reading, ShakeThreshold))
                    {
                        _shakeCount++;
                    }
                    else if (!CheckForShake(_lastReading, reading, 0.2))
                    {
                        _shakeCount = 0;
                        _shaking = false;
                    }
                }
                _lastReading = reading;
            }
            catch
            {
                /* ignore errors */
            }
        }
    }

    private void OnShakeDetected()
    {
        if (ShakeDetectedHandler != null)
            ShakeDetectedHandler(this, EventArgs.Empty);
    }

    private static bool CheckForShake(AccelerometerReadingEventArgs last, AccelerometerReadingEventArgs current,
                                        double threshold)
    {
        double deltaX = Math.Abs((last.X - current.X));
        double deltaY = Math.Abs((last.Y - current.Y));
        double deltaZ = Math.Abs((last.Z - current.Z));

        return (deltaX > threshold && deltaY > threshold) ||
                (deltaX > threshold && deltaZ > threshold) ||
                (deltaY > threshold && deltaZ > threshold);
    }
}

And of course you want to use it in your app, which can be done like this.

_shakeSensor = new AccelerometerSensorWithShakeDetection();
Loaded += (sender, args) =>
                {
                    _shakeSensor.ShakeDetected += ShakeDetected;
                    _shakeSensor.Start();
                };
Unloaded += (sender, args) =>
                {
                    _shakeSensor.ShakeDetected -= ShakeDetected;
                    _shakeSensor.Stop();
                };
Be aware that the event is fired on a different thread, so if you want to use this in the UI thread you might want to read an old article on UI threads from my hand.
  • Gravatar AlexH November 3rd, 2010 at 22:07
    Hi Mark,
    I'm seeking your permission to reuse this code in some examples for WP7 Hands-On-Labs. Can you contact me please?
    Thank you.
  • Gravatar Chris Rae November 11th, 2010 at 06:52
    This is a great article - you have a couple of tiny omissions. Firstly you somehow don't actually assign the sensor ReadingChanged event handler, so your code:

    add
    {
    ShakeDetectedHandler += value;
    }

    Should actually read:


    add
    {
    ShakeDetectedHandler += value;
    _sensor.ReadingChanged += ReadingChanged;
    }


    And secondly you don't mention that in your code you need a ShakeDetected handler, i.e.:


    private void ShakeDetected(object sender, EventArgs e)
    {
    }


    Great article, though - saved me a ton of work!
  • Gravatar Luke Lowrey November 29th, 2010 at 08:47
    Awesome code. Might implement me some shake to refresh.
  • Gravatar Edwin Evans December 14th, 2010 at 02:21
    Thanks! I used this in my Bubbles Magic app ( http://www.youtube.com/watch?v=vw1aw7I4Nyc ) to pop all the bubbles :)
Gravatar