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

  • Compare New GitHub Copilot Free Plan for Visual Studio/VS Code to Paid Plans

    The free plan restricts the number of completions, chat requests and access to AI models, being suitable for occasional users and small projects.

  • Diving Deep into .NET MAUI

    Ever since someone figured out that fiddling bits results in source code, developers have sought one codebase for all types of apps on all platforms, with Microsoft's latest attempt to further that effort being .NET MAUI.

  • Copilot AI Boosts Abound in New VS Code v1.96

    Microsoft improved on its new "Copilot Edit" functionality in the latest release of Visual Studio Code, v1.96, its open-source based code editor that has become the most popular in the world according to many surveys.

  • AdaBoost Regression Using C#

    Dr. James McCaffrey from Microsoft Research presents a complete end-to-end demonstration of the AdaBoost.R2 algorithm for regression problems (where the goal is to predict a single numeric value). The implementation follows the original source research paper closely, so you can use it as a guide for customization for specific scenarios.

  • Versioning and Documenting ASP.NET Core Services

    Building an API with ASP.NET Core is only half the job. If your API is going to live more than one release cycle, you're going to need to version it. If you have other people building clients for it, you're going to need to document it.

Subscribe on YouTube