Windows Phone devices are modern devices. As such, they usually have few sensors such as built-in accelerometer, A-GPS, light sensor, magnetometer, etc. Windows Phone minimum hardware spec requires that all Windows Phone will have at least 4 of them – A-GPS, Accelerometer, Compass and Light sensors. While accelerometer and A-GPS were available for developers with first version of Windows Phone, there are some new sensors which were added with Mango. The hardware market is not standing still, thus we could see much advanced sensors coming out on the modern phone models. Some of those sensors (like gyro for example) were added to Mango API. The table below provides quick compare between RTM and Mango sensors support:
|Sensor||Windows Phone RTM||Windows Phone Mango|
In some case, even when the sensor hardware component installed on the device it doesn’t mean that is have the managed (.NET) API to access it (for example light sensor).
Mango tools provide better developers support while developing sensors-enables application. In previous release developing accelerometer-enabled or A-GPS-enabled (location-aware) applications required real developer-unlocked phone device or some community solution to emulate sensors input. With Mango release this support provided by Windows Phone Emulator. To emulate accelerometer or location readings open “Additional Tools” windows of emulator:
The opened “Addition Tools” window enables accelerometer and location changes emulation. To simulate the accelerometer data, move the pink “ball” with you mouse:
The Location tab enables not only to send current location to the Windows Phone Emulator, but also to record the geographical point and send them at given time interval to emulate the device movement:
One important note here: while the Windows Phone Emulator provides you a way to simulate the accelerometer and GPS location data, it is advised to check your application also in real device, since real sensors data is subject to environmental influence, network availability, magnetic fields, etc. Always check you application on the real device to see how it behaves under real-world conditions.
Now let’s get back to the sensors. I will cover the changes (or actually additions) to he Camera in next post and focus to new sensors in this post.
All sensor classes in Mango derive from single base class, SensorBase<T>, which makes developer life really easy. All the sensors will be initialized and operated the same way. Only the events and readings data vary between different sensors.
Let’s see common parts of sensors interface:
|Base Class Member||Info|
|CurrentValue||Property, contains current value of the sensor|
|IsDataValid||Property, contains the validity of the sensor’s data|
|CurrentValueChanged||Event, occurs when new data arrives from the sensor|
|TimeBetweenUpdates||Property, gets or sets the preferred time between CurrentValueChanged events|
|Start||Function, starts acquisition of data from the sensor|
|Stop||Function, stops acquisition of data from the sensor|
|Dispose||Function, releases the managed and unmanaged resources used by the sensor|
In general, the pattern to work with the sensor should be as the following:
1. The sensor variable defined at the class level and available for all functions in the class (page).
//Class level variable
2. Activate the sensor at the latest possible time. Usually OnNavigatedTo event handler is good place for it:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
motion = new Motion();
//Subscribe to sensor-specific events
motion.Calibrate += new EventHandler<CalibrationEventArgs>(motion_Calibrate);
motion.CurrentValueChanged += new EventHandler<SensorReadingEventArgs<MotionReading>>(motion_CurrentValueChanged);
//Always have a backup plan for non-supported sensor scenario!
Subscribe to sensor-specific events (only those you actually need) and always have a backup plan when the sensor is not supported on the device.
3. Release the sensor at earliest possible time and unsubscribe from events:
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
//If sensor were initialized
if (null != motion)
//Unsubscribe from sensor-specific events
motion.Calibrate -= motion_Calibrate;
motion.CurrentValueChanged -= motion_CurrentValueChanged;
//Stop the readings flow and release
motion = null;
4. Keep in mind, that the CurrentValueChanged (and other) event handlers will not arrive on UI thread. If your code need to change some on-screen element properties, use Dispatcher:
void motion_CurrentValueChanged(object sender, SensorReadingEventArgs<MotionReading> e)
//Schedule UI related work to dispatcher queue
imageProjection.RotationY = e.SensorReading.Attitude.Pitch * bankLimit;
imageProjection.RotationX = e.SensorReading.Attitude.Roll * angleOfAttackLimit;
imageProjection.RotationZ = e.SensorReading.Attitude.Yaw * yawLimit;
In addition to the base class members, all sensors adds some specific logic and functionality. The sample code above represents Motion sensor functionality. This sensor is a new virtual sensor which combines gyroscope, compass and accelerometer reading with some mathematic calculations needed to identify the device orientation, device movement, the gravity, etc. Those values are ready to be consumed by the applications. The motion sensors gives most accurate information since it combines all sensors and eliminates possible sensor accuracy problems when single sensor is used. This sensor is recommended to use when available.
The availability of this sensor and the readings quality depends on availability of other sensors and represented below:
|Yes||Yes||Yes||Yes, full quality|
|Yes||Yes||No||Yes, degraded quality|
Compass sensor (aka magnetometer sensor) the following data to the application:
- HeadingAccuracy — The accuracy of compass heading readings in degrees. We will use this value later for compass calibration
- MagneticHeading — The compass heading relative to Earth’s magnetic north (provided in degrees)
- TrueHeading — The compass heading relative to Earth’s geographic north (provided in degrees)
- MagnetometerReading — The raw magnetometer reading values in microteslas (values provided in XNA’s Vector3 type. To use those readings you are required to add a reference to Microsoft.Xna.Framework assembly)
In addition, compass sensor enables application to subscribe to the Calibrate event, since magnetometer sensor which used to implement the compass is subject to external interference. Metal obstacles, high-voltage electrical installations and some electronic devices could interfere with Earth’s magnetic field and change the local magnetic field’s values. In case the sensor needs to be calibrated and the compass API fires the Calibrate event. When this event fired the application have to present the UI with instructions to perform sensor calibration. Sensor calibration performed by waving the device in figure 8 pattern:
The API doesn’t provide any “CalibrationComplete” notification, and it is up to developer to decide when data accuracy sufficient to the application. In general, HeadingAccuracy below 10-15 degrees should enough for most applications. This means that your calibration code should look like the follows:
void compass_Calibrate(object sender, CalibrationEventArgs e)
//Show calibration instructions
stkCalibration.Visibility = Visibility.Visible;
//Hide compass sensor related UI
imgRose.Visibility = Visibility.Collapsed;
//Set “Is Calibrating” flag to consume it later
compassCalibrating = true;
Then, in CurrentValueChanged event handler check if compass already calibrated to hide the calibrating instructions:
void compass_CurrentValueChanged(object sender, SensorReadingEventArgs<CompassReading> e)
//Check is compass is calibrating
//Check if current HeadingAccuracy below threshold value
if (e.SensorReading.HeadingAccuracy < 10)
//Compass calibrated, restore the compass UI
compassCalibrating = false;
//The compass reading are not guaranteed to arrive in UI thread
imgRose.Visibility = Visibility.Visible;
stkCalibration.Visibility = Visibility.Collapsed;
ContentPanel.Background = new SolidColorBrush(Colors.Transparent);
imageRotation.Angle = e.SensorReading.TrueHeading;
This code hides the calibration UI and display the compass UI I’m using in this sample:
Note: same calibration procedures applies also on motion sensor
Last new sensor in Mango is a Gyroscope. A gyroscope is a device for measuring or maintaining orientation, based on the principles of conservation of angular momentum. In Mango, Gyroscope API provides the rotational velocity around each one of 3 axis (X, Y and Z) of the device in radians per second.
Note: Since gyroscope is relatively rare sensor in current generation of Windows Phone devices it very important to have a fallback plan in case it is not supported
The GyroscopeReading class (an instance of CurrentValue) class provides us with gyroscope’s RotationRate – the rotational velocities around each one of 3 axis of the device, and Timestamp which indicates when the reading was taken.
That’s it about new sensors in Mango. Sample used to demonstrate it hosted here.
Stay tuned to the part 4 – “Camera”