Mono for Android

Location in Mono for Android

Learn about Android's sensors by building a simple compass application.

Like real estate, mobile is about location, location, location. That means that direction is an important item. And just as important is how this information is presented to the user. In Nov. 2011, we talked about building a user interface in Mono For Android. In this article, I'll expand a little bit on that by creating a compass that displays north. We'll use Android's built-in sensor support to determine the orientation of the device, then use a custom control to display North. The output will look like Figure 1.


[Click on image for larger view.]
Figure 1. The completed application.
Sensors and the World around Us
Android is a full-fledged operating system. One thing that means is it can determine the state of its surroundings. It does this via a technology called Sensors. Sensors allow an Android device to detect its environment and that of the user. The types of sensors supported are defined in the Android.Hardware.SensorType enumeration. This enumeration has the values show in Table 1, along with the values returned in the OnSensorChanged event:

Table 1. Android Sensors.


Sensor Type

Explanation

Values Returned

Accelerometer

Acceleration of the device in the x, y, and z coordinate system. The units are in meters per second^ 2.

value[0] – Lateral
value[1] – Longitudinal
value[2] – Vertical

MagneticField

This measures the ambient magnetic field in the x, y, and z coordinate system. The units returned are in micro Teslas.

value[0] – Lateral
value[1] – Longitudinal
value[2] – Vertical

Gyroscope

This measures the rotation of the device in the x, y, and z coordinate system. The units returned are in radians per second.

value[0] – Azimuth
value[1] – Pitch
value[2] – Roll

Light

This measures the ambient light on the device. The units returned are in SI lux units.

value[0]

Proximity

This is useful for detecting if the device is close to a user's face. The units returned are in meters.

value[0]

Orientation

This measures the orientation of the device along the x, y, and z coordinate system. The units returned are in degrees.

value[0] – Azimuth
value[1] – Pitch
value[2] – Roll

Pressure

A measure of the pressure on the device. The units returned are in kilopascals.

value[0]

Temperature

This is a measure of the temperature. The temperature will depend on the location of the sensor in the device. The units returned are in Celsius.

value[0]

The code in Listing 1 returns the device's orientation. Several things are important to note:

  • The activity implements the ISensorEventListener interface. By implementing this interface, we can get information from the device hardware regarding the Sensors.
  • There are two methods that must be implemented: OnAccuracyChanged and OnSensorChanged. Inside the OnSensorChanged event, notice that the code performs a test to determine what sensor the values are coming from.

Remember that Sensors can return any number of values from various pieces of hardware, and that the values may have different dimensions than others. For example, if there's a need to track orientation and temperature at the same time, care must be taken to determine the sensor that returns a value, as well as the dimensions of the values that have been returned.

  • While not seen in this example, values returned from a sensor are returned on a separate thread. If code is writing directly to the UI, a call to RunOnUIThread is likely going to be required.
  • Pay attention to registering a listener through the SensorManager. It makes sense to start listening in the OnCreate method of the Activity. It also makes sense to quit listening sometimes; for example, when the activity is paused, goes into the background, or does something else that removes this activity from the foreground. By stopping the listener, the battery will have a bit more charge, making the application a good device citizen. Turn off listeners whenever you can.
  • When a listener is registered, the application can request how often the sensor updates the activity. This is done via the SensorDelay enum.

Creating the Custom Control
Now that we have seen how to receive listener updates from the sensors, the next step is to update our user interface to draw the orientation. The first step is to create and display the compass. In this example, it's done programmatically by adding our CompassView class to our LinearLayout. This is done through the OnCreate method.

Notice in the OnSensorChanged method that there's a call to the CompassView instance to pass along the new directional value. Listing 2 shows the code for the CompassView class. Note several important methods:

  • The updateDirection method communicates from the front-end activity to the CompassView instance, and passes in a new direction for the orientation. When a new value is passed in, the view's .invalidate method is called. The invalidate method forces a view to refresh. If the view's visible, the classes' OnDraw method is called.
  • The .OnDraw method draws on the canvas, which contains the drawing area and background. Inside this method, the code redraws the rectangle holding the compass, the circle, the line showing the orientation, and the text, with the orientation in degrees.
  • The .OnMeasure method is responsible for determining the width and height of the  drawing area.
  • There are other methods the code can override from the View class. Because this class inherits from the View class, any methods or properties the View class has are available to be overridden.

Drawing Content
After stepping through the details of the code, it's possible to understand what's happening at a high level. To draw the content:

  • Instantiate the CompassView in the activity
  • Get the value of North from the sensors
  • Pass the value of North to the instance of the CompassView
  • Invalidate the CompassView and allow it to redraw itself via the OnDraw method
  • Display the output to the user

We've now created a compass and displayed its output to the user in a graphic way that approximates the type of compass we had as kids.

Thanks to Kevin Darty for proofing and technical feedback on this article.

About the Author

Wallace (Wally) B. McClure has authored books on iPhone programming with Mono/Monotouch, Android programming with Mono for Android, application architecture, ADO.NET, SQL Server and AJAX. He's a Microsoft MVP, an ASPInsider and a partner at Scalable Development Inc. He maintains a blog, and can be followed on Twitter.

comments powered by Disqus

Featured

  • Creating Reactive Applications in .NET

    In modern applications, data is being retrieved in asynchronous, real-time streams, as traditional pull requests where the clients asks for data from the server are becoming a thing of the past.

  • AI for GitHub Collaboration? Maybe Not So Much

    No doubt GitHub Copilot has been a boon for developers, but AI might not be the best tool for collaboration, according to developers weighing in on a recent social media post from the GitHub team.

  • Visual Studio 2022 Getting VS Code 'Command Palette' Equivalent

    As any Visual Studio Code user knows, the editor's command palette is a powerful tool for getting things done quickly, without having to navigate through menus and dialogs. Now, we learn how an equivalent is coming for Microsoft's flagship Visual Studio IDE, invoked by the same familiar Ctrl+Shift+P keyboard shortcut.

  • .NET 9 Preview 3: 'I've Been Waiting 9 Years for This API!'

    Microsoft's third preview of .NET 9 sees a lot of minor tweaks and fixes with no earth-shaking new functionality, but little things can be important to individual developers.

  • Data Anomaly Detection Using a Neural Autoencoder with C#

    Dr. James McCaffrey of Microsoft Research tackles the process of examining a set of source data to find data items that are different in some way from the majority of the source items.

Subscribe on YouTube