The Accelerometer records the device acceleration in three dimensions, that is, along the x, y, and z axis. Almost all phones are now shipped with an accelerometer as it's a pretty old technology. Indeed, the very first phone to have one was the Apollo 11 Lunar Module. A phone with wheels. Actually, the first mainstream and terrestrial phone equipped with this technology was the Samsung SCH-S310 in 2005 on which you could dial numbers by writing them in the air. Today's application of the accelerometer are almost all related to games. In this recipe, we will detect if the phone is falling; this can be useful for the elderly in the sense that we can be warned of emergencies automatically.
To follow this recipe, create a new project called Accelerometer
. Similar to the previous recipe, you'll have to deploy your code on a physical phone as the emulator doesn't support the accelerometer.
Now, we will see how to use the accelerometer and other sensors:
using Android.Hardware
and using System.Text
instances at the top of your MainActivity
class.textview
element in your Resources
/layout
/Main.axml
file and name it myTextView
.MainActiviy
class implement the ISensorEventListener
interface:public class MainActivity : Activity, ISensorEventListener
MainActivity
class:private static readonly object myLock = new object(); private SensorManager mySensorManager; private float x=0, y=0, z=0; private TextView myTextView;
OnCreate()
method so that it looks like the following:protected override void OnCreate(Bundle bundle) { base.OnCreate(bundle); SetContentView(Resource.Layout.Main); mySensorManager = (SensorManager) GetSystemService(SensorService); myTextView = FindViewById<TextView>(Resource.Id.myTextView); mySensorManager.RegisterListener(this, mySensorManager.GetDefaultSensor(SensorType.Accelerometer), SensorDelay.Ui); }
OnSensorChanged
function from the ISensorEventListener
interface:public void OnSensorChanged(SensorEvent e) { StringBuilder text = new StringBuilder (); lock (myLock) { float currentX = e.Values [0]; float currentY = e.Values [1]; float currentZ = e.Values [2]; // First time if (z == 0 && y == 0 && z == 0) { z = currentZ; y = currentY; x = currentX; } else if (Math.Abs (currentX / x) > 2 || Math.Abs (currentY / y) > 2 || Math.Abs (currentZ / z) > 2) { z = currentZ; y = currentY; x = currentX; text.Append ("Is Probably Falling"); } text.Append("x = ") .Append(currentX) .Append(", y=") .Append(currentX) .Append(", z=") .Append(currentZ); myTextView.Text = text.ToString(); } }
OnAccuracyChanged()
function from ISensorEventListener
, which receives [Android.Runtime.GeneratedEnum] SensorType sensor
and [Android.Runtime.GeneratedEnum] SensorStatus
as parameters and leaves its body blank.textview
element to be refreshed with new values. If you move the phone fast enough, The Label Is Probably Falling will appear before the x, y, and z accelerations.Each sensor's data can be accessed through background services. In order for our application to be fed by the data of a sensor, we need to create a reference to the SensorManager
instance. Finally, we can register our application via a Listener
instance, so the OnSensorChanged()
method will be triggered every time the sensor changes its value.
To acquire a reference to the SensorManager
instance, we simply use the GetSystemService()
helper as follows:
mySensorManager = (SensorManager) GetSystemService(SensorService);
Then, we register our application to receive the data from the accelerometer as follows:
mySensorManager.RegisterListener(this, mySensorManager.GetDefaultSensor(SensorType.Accelerometer), SensorDelay.Ui);
In the OnSensorChanged()
method, we implemented a C# thread-safe lock as this method can be retriggered before it finishes its execution:
lock (myLock)
Then, we retrieve the values of the acceleration for the three axes and compare them with the previous values. If the division results is more than two (value of accelerometer) on one of the three axes, it likely means that the phone is falling:
float currentX = e.Values [0]; float currentY = e.Values [1]; float currentZ = e.Values [2]; // First time if (z == 0 && y == 0 && z == 0) { z = currentZ; y = currentY; x = currentX; } else if (Math.Abs (currentX / x) > 2 || Math.Abs (currentY / y) > 2 || Math.Abs (currentZ / z) > 2) { z = currentZ; y = currentY; x = currentX; text.Append ("Is Probably Falling"); }
Android phones can be equipped with a very large range of sensors that can be used in the same way as the accelerator. They are categorized in three categories: motion, position, and environment. For each of them, you'll have to register your activity as follows:
mySensorManager.RegisterListener(this, mySensorManager.GetDefaultSensor(SensorType.MY_TYPE), SensorDelay.MY_FREQ);
Here SensorType.MY_TYPE
and SensorType.MY_FREQ
have to be adapted to your needs.
While we can easily discover the different sensors using the Intellisense of Xamarin, the data they return is only float. In what follows, I report what those floats represent.
Here, I present the different values that can be retrieved for motion sensors:
SensorEvent.value[0]
: This is the acceleration force on x axisSensorEvent.value[1]
: This is the acceleration force on y axisSensorEvent.value[2]
: This is the acceleration force on z axisSensorEvent.value[0]
: This is the gravity force on x axisSensorEvent.value[1]
: This is the gravity force on y axisSensorEvent.value[2]
: This is the gravity force on z axisSensorEvent.value[0]
: This is the rotation on x axisSensorEvent.value[1]
: This is the rotation on y axisSensorEvent.value[2]
: This is the rotation on z axisSensorEvent.value[0]
: This is the acceleration force on x axis without gravitySensorEvent.value[1]
: This is the acceleration force on y axis without gravitySensorEvent.value[2]
: This is the acceleration force on z axis without gravitySensorEvent.value[0]
: This is the rotation on x axisSensorEvent.value[1]
: This is the rotation on y axisSensorEvent.value[2]
: This is the rotation on z axisonSensorChanged()
method when a significant movement is detected.SensorEvent.value[0]
: This is the number of steps since the last activation of the sensoronSensorChanged()
method when a step is detectedIn what follows, I present the different values that can be retrieved for position sensors:
SensorEvent.value[0]
: This is the rotation on x axisSensorEvent.value[1]
: This is the rotation on y axisSensorEvent.value[2]
: This is the rotation on z axisSensorEvent.value[0]
: This is the rotation on x axisSensorEvent.value[1]
: This is the rotation on y axisSensorEvent.value[2]
: This is the rotation on z axisSensorEvent.value[0]
: This is the geomagnetic field on x axisSensorEvent.value[1]
: This is the geomagnetic field on y axisSensorEvent.value[2]
: This is the geomagnetic field on z axisSensorEvent.value[0]
: This is the distance with the objectAndroid provides four different rates at which you can refresh your sensors' data. The faster rate is the most accurate and will consume much more battery. You have to evaluate your needs and choose the right trade-off between accuracy and battery consumption for your applications. The four different rates are as follows:
SensorDelay.Fastest
: This rate is the fastest possible rateSensorDelay.Game
: This is a suitable rate for gamesSensorDelay.Normal
: This is a suitable rate for screen orientation changeSensorDelay.UI
: This is a suitable rate for graphical interfacesIn order to enhance the battery life of the phones your applications are running on, it is a good practice, if possible, to listen to the sensors only when your application is displayed. To accomplish this, we can register ourselves using the OnResume()
method and unregister ourselves using the OnPause()
method. Consequently, our application will only consume the sensors' data when displayed:
protected override void OnResume() { base.OnResume(); mySensorManager.RegisterListener(this, mySensorManager.GetDefaultSensor(SensorType.Accelerometer), SensorDelay.Ui); } protected override void OnPause() { base.OnPause(); mySensorManager.UnregisterListener(this); }
18.222.83.185