
Nowadays almost every mobile phone is equipped with a large variety of different sensors that developers can use to know a little more about the surrounding environment, and thus improve the user experience for their applications.
In this tutorial I’m going to show you how you can retrieve different types of sensors data from your Bada phone.
Since the whole tutorial was too long for a single post I sliced it down into two parts, welcome to part 1 “Theory and setup”.
As always a sample app is available on GitHub, I suggest you to git clone or download it and keep it at hand while reading this post.
To introduce this topic let’s make a list of the sensors that you can normally find on a Bada device, maybe other sensors will be available in the future, but now we have these:
The Acceleration sensor is a 3 axis (x,y,z) accelerometer sensor used to determine changes in velocity. It provides the three dimensional acceleration vector components expressed in g, which is the standard unit of measure for the acceleration. One g corresponds to the acceleration due to the Earth’s gravity (1 g = 9.8 m/s^2).
Note that since you’ll be using this sensor mostly on Earth (if not, please let me know!) a 1 g acceleration value is what you’ll get from this sensor if you lay down the device not moving it. The direction of the acceleration vector however depends on how the device is positioned.
If you need accurate acceleration measures you’ll have to take this default 1 g value into account and adjust your measures accordingly, it can be done by determining the phone orientation with the tilt sensor. However this is not what we are trying to do here, so let’s move on.
The Magnetic sensor is a 3 axis (x,y,z) magnetic field sensor. It can be used to sense magnetic fields or to find the device orientation with respect to the Earth’s magnetic field when combined with the acceleration sensor. This sensor provides the three dimensional magnetic field vector components expressed in microTesla (µT).
The Proximity sensor is a digital (0-1, on-off) sensor used to determine the presence of an object near the device. On wave phones this sensor is usually placed on the top-right corner, just above the screen.
The Tilt sensor provides high level information such as the pitch (rotation along the x axis), roll (rotation along the z axis) and the azimuth angle (rotation along the y axis) by combining acceleration and magnetic sensors data, this sensor is very useful if you want to implement a compass functionality because it provides all you need (which is the azimuth angle).
All the Bada APIs used to access data from sensors can be found inside a namespace named Osp::Uix. Uix stands for User Interface eXtensions, this namespace provides some cool APIs that you can use to improve your user interface like faces detection, faces recognition, and many others including, of course, the sensors APIs that we are going to use now.
On Bada you never read sensor data directly, instead you can receive them from the operating system at fixed intervals in time.
Like many other operations in Bada development, reading data from sensors can be easily done by implementing an event listener interface and registering it to an operating system component which will then deliver sensor events (and thus sensor data) to your event listener at fixed time intervals.
The operating system component that delivers sensor data at fixed intervals is the SensorManager, while the event listener interface that you use to receive them is the ISensorEventListener; both of them are wrapped inside the Osp::Uix namespace.
Before we start coding this down, here’s a list of the classes/types that we are going to use, with a brief explanation:
- Osp::Uix::ISensorEventListener: receives sensors events (and data) from the SensorManager.
- Osp::Uix::SensorManager: delivers sensors data to registered ISensorEventListener instances.
- Osp::Uix::SensorData: contains sensors data, the SensorManager delivers sensors data to registered event listeners using this class.
- Osp::Uix::SensorType: it’s a numeric value that identifies a sensor type:
- SENSOR_TYPE_ACCELERATION
- SENSOR_TYPE_MAGNETIC
- SENSOR_TYPE_PROXIMITY
- SENSOR_TYPE_TILT
Setup & Configurations
The sample app is made of one form named DataForm which implements the sensor event listener interface:
// DataForm.h #include <FBase.h> #include <FUi.h> #include <FUix.h> #include <FSystem.h> class DataForm : public Osp::Ui::Controls::Form, public Osp::Uix::ISensorEventListener { ... private: /* Osp::Uix::ISensorEventListener methods */ virtual void OnDataReceived(Osp::Uix::SensorType sensorType, Osp::Uix::SensorData &sensorData, result r); ... private: /* SensorManager */ Osp::Uix::SensorManager sensorManager; ... private: /* Ui Controls */ Osp::Ui::Controls::Label * pAccelerationXValueLabel; Osp::Ui::Controls::Label * pAccelerationYValueLabel; Osp::Ui::Controls::Label * pAccelerationZValueLabel; Osp::Ui::Controls::Label * pMagneticXValueLabel; Osp::Ui::Controls::Label * pMagneticYValueLabel; Osp::Ui::Controls::Label * pMagneticZValueLabel; Osp::Ui::Controls::Label * pPitchValueLabel; Osp::Ui::Controls::Label * pRollValueLabel; Osp::Ui::Controls::Label * pAzimuthValueLabel; Osp::Ui::Controls::Label * pProximityValueLabel; } |
As you can see the ISensorEventListener interface only requires one method to be implemented (OnDataReceived()), the SensorManager calls this method every x milliseconds (depending on the configured time interval) and on every registered event listener to deliver sensors data.
The SensorManager passes the values from the different sensors as parameters to this method.
We’ll learn how to read them.
The sensorManager private member is the Osp::Uix::SensorManager instance that will deliver sensors data to our DataForm.
The 10 Osp::Ui::Controls::Label members are used to show the sensors values to the user, they will be bound to 10 labels components that have been added to the xml form, on the right you can see an image of the form and the label’s names that will be used inside the initialization code to access them from the code side.
The initialization code is placed inside the DataForm::OnInitializing() method.
Here’s a step by step explanation of the initialization code:
#include "DataForm.h" using namespace Osp::Base; using namespace Osp::Base::Collection; using namespace Osp::Ui; using namespace Osp::Ui::Controls; using namespace Osp::Uix; ... ... result DataForm::OnInitializing(void) { result r = E_SUCCESS; |
The first thing to do is initializing the Label components that will show the sensors data to the user, this is done as always with the GetControl() method:
pAccelerationXValueLabel = static_cast<Label *> (GetControl(L"IDC_ACCEL_X_VAL_LABEL")); pAccelerationYValueLabel = static_cast<Label *> (GetControl(L"IDC_ACCEL_Y_VAL_LABEL")); pAccelerationZValueLabel = static_cast<Label *> (GetControl(L"IDC_ACCEL_Z_VAL_LABEL")); pMagneticXValueLabel = static_cast<Label *> (GetControl(L"IDC_MAG_X_VAL_LABEL")); pMagneticYValueLabel = static_cast<Label *> (GetControl(L"IDC_MAG_Y_VAL_LABEL")); pMagneticZValueLabel = static_cast<Label *> (GetControl(L"IDC_MAG_Z_VAL_LABEL")); pPitchValueLabel = static_cast<Label *> (GetControl(L"IDC_PITCH_VAL_LABEL")); pRollValueLabel = static_cast<Label *> (GetControl(L"IDC_ROLL_VAL_LABEL")); pAzimuthValueLabel = static_cast<Label *> (GetControl(L"IDC_AZIMUTH_VAL_LABEL")); pProximityValueLabel = static_cast<Label *> (GetControl(L"IDC_PROX_VAL_LABEL")); |
Next thing to do is to construct the SensorManager instance, which like any other bada components follows the two phase construction idiom:
/* Initialize the SensorManager */ r = sensorManager.Construct(); if (IsFailed(r)) { AppLog("Error: cannot construct the SensorManager: %s", GetErrorMessage(r)); return E_FAILURE; } |
Before you start receiving data from a sensor you have to determine two points:
- Whether or not that sensor is available.
- The time interval at which sensors data will be delivered to your sensor event listener.
Both of them can be determined by using specific APIs exposed by the SensorManager class.
The first point is quite easy to understand: your code could run on a Bada device that does not mount the sensor you are trying to register for, so instead of crashing we can simply print out an error message and handle the error condition more gracefully.
Here’s the APIs to check the sensor availability:
/* Returns true if the specified sensor is available in this device, Returns false if the sensor is not available */ bool Osp::Uix::SensorManager::IsAvailable(SensorType sensorType); |
The second point is quite easy too, once you know the whys.
Decide how often you want to receive sensors data.
In other words you have to find the best update frequency, not too often and not too seldom, depending on what you have to do with these data.
If you are designing an accelerometer based game control you are certainly going to need a high precision and a high responsiveness, so the smallest time interval between each sensor data delivery is the best choice for you.
However a smaller time interval can also mean a shorter battery life, because the operating system performs more sensor reads consuming more power.
This last sentence can sound a bit paranoid, I know, but it’s way better to never underestimate the power cost of these kinds of operations. Keep in mind that before being sent to your event listener these data are usually processed by one or more filtering algorithm (like the Kalman filer and others) in order to reduce the noise and provide better results to your code to work with.
Each sensor supports a maximum and a minimum update interval so you cannot use an arbitrary value; it must fall inside the maximum and the minimum supported intervals or you will get an error and your code won’t work.
Every sensor has different hardware specifications, and it’s very likely to happen that different phones use different sensors with different supported update-time intervals.
For this reason it’s definitely a bad idea to hard code a time interval to use on all devices.
Fortunately Bada provides some APIs to retrieve the maximum and the minimum supported interval for each sensor, the values returned by these APIs are in milliseconds and you can use them to determine the best interval to suit your needs.
Here’s the APIs to use:
/* Returns the minimum supported time interval for the specified sensor */ result Osp::Uix::SensorManager::GetMinInterval(SensorType sensorType, long & interval); /* Returns the maximum supported time interval for the specified sensor */ result Osp::Uix::SensorManager::GetMaxInterval(SensorType sensorType, long & interval); |
Once we found that the sensor is available and determined the optimal update frequency we can move on and register the ISensorEventListener to the SensorManager.
To register a sensor event listener we can use this API:
result Osp::Uix::SensorManager::AddSensorListener(const ISensorEventListener & listener, SensorType sensorType, long interval, bool dataChanged); |
The listener parameter will be a reference to our DataForm which implements the ISensorEventListener interface.
The sensorType will be one of the possible values, we will make four calls to this API one for each sensorType.
The interval parameter is the update interval time in milliseconds.
If the dataChanged parameter is true you will receive sensors data updates only if they are changed since the last update. In other words if the interval is 10 milliseconds and dataChanged is true then you are not guaranteed to receive sensors data every 10 milliseconds, you’ll receive them only if they are changed since the last update.
This is the recommended choice, because having data from four different sensors delivered every 10 milliseconds would create a great execution overhead sucking your battery and probably freezing the whole system. Unless you really need it always set the dataChanged flag to true.
The sample application receives all sensors data at the minimum supported time interval and only if sensors data are changed since the previous update (dataChanged = true), here’s the code that registers the sensor event listener for the acceleration sensor:
long minimumSensorInterval; /* Check if this sensor is available */ if (sensorManager.IsAvailable(SENSOR_TYPE_ACCELERATION)) { /* Obtain the minimum supported time interval between each read */ sensorManager.GetMinInterval(SENSOR_TYPE_ACCELERATION, minimumSensorInterval); /* Add the sensor event listener (this form) to the sensor manager */ sensorManager.AddSensorListener(*this, SENSOR_TYPE_ACCELERATION, minimumSensorInterval, true); /* Check for errors */ if (IsFailed(r)) return E_FAILURE; } |
The same code is used again three more times to register the event listener for the tilt, magnetic and proximity sensors, the only thing that changes is the sensorType parameter:
if (sensorManager.IsAvailable(SENSOR_TYPE_TILT)) { sensorManager.GetMinInterval(SENSOR_TYPE_TILT, minimumSensorInterval); sensorManager.AddSensorListener(*this, SENSOR_TYPE_TILT, minimumSensorInterval, true); if (IsFailed(r)) return E_FAILURE; } if (sensorManager.IsAvailable(SENSOR_TYPE_MAGNETIC)) { sensorManager.GetMinInterval(SENSOR_TYPE_MAGNETIC, minimumSensorInterval); sensorManager.AddSensorListener(*this, SENSOR_TYPE_MAGNETIC, minimumSensorInterval, true); if (IsFailed(r)) return E_FAILURE; } if (sensorManager.IsAvailable(SENSOR_TYPE_PROXIMITY)) { sensorManager.GetMinInterval(SENSOR_TYPE_PROXIMITY, minimumSensorInterval); sensorManager.AddSensorListener(*this, SENSOR_TYPE_PROXIMITY, minimumSensorInterval, true); if (IsFailed(r)) return E_FAILURE; } |
Now our DataForm is able to receive sensors data from all the sensors.
Before trying to do any other thing let’s implement the cleanup code to un-register the sensors event listeners when the DataForm is terminated, this can be done inside the DataForm::OnTerminating() method which will be called by the system right before the DataForm is removed from the main application frame.
The APIs used to un-register a sensor event listener is this one:
result Osp::Uix::SensorManager::RemoveSensorListener(const ISensorEventListener & listener, SensorType sensorType); |
I’ll let you imagine what we should pass as parameters and move on to the code:
result DataForm::OnTerminating(void) { result r = E_SUCCESS; if (sensorManager.IsAvailable(SENSOR_TYPE_ACCELERATION)) sensorManager.RemoveSensorListener(*this, SENSOR_TYPE_ACCELERATION); if (sensorManager.IsAvailable(SENSOR_TYPE_TILT)) sensorManager.RemoveSensorListener(*this, SENSOR_TYPE_TILT); if (sensorManager.IsAvailable(SENSOR_TYPE_MAGNETIC)) sensorManager.RemoveSensorListener(*this, SENSOR_TYPE_MAGNETIC); if (sensorManager.IsAvailable(SENSOR_TYPE_PROXIMITY)) sensorManager.RemoveSensorListener(*this, SENSOR_TYPE_PROXIMITY); return r; } |
This will stop the updates from every sensors, preventing resources leaks and any other problem.
This is all for now, the next post will show you the code to read the sensors data and display them to the user, however you can take a look at the sample app is available on GitHub if you are in a hurry, it’s all pretty well commented and should be straightforward to understand (I hope)!
So, come back in a few days for the next part! And..
“May The Schwartz Be With You!” – (Yogurt)




