How to make a Compass Android App

 

TO: Prof. Jason Ellis

FROM: Ali Hossain

DATE: 04/12/2021

SUBJECT: Instruction manual

How to make a Compass Android App

Ali Hossain

BTech in Computer Information Technology

New York City College of Technology

This user manual was created as a class project in ENG2575, OL88, Spring 2021.

1.0 Introduction and Purpose

2.0 List of Materials and Equipment Needed

3.0 Setting up the Required Permissions

4.0 Designing the GUI of the App

5.0 Writing the Main Code of the App

6.0 Building and Running the App

7.0 Troubleshooting

8.0 References

 

 

1.0 Introduction and Purpose

We’ll develop a simple compass app that will utilize the internal accelerometer and magnetometer sensors of the Android device. Accelerometer is a sensor which converts the mechanical acceleration information to electrical signals and similarly a magnetometer is used to translate the magnetic field intensity to electronic signals.

Most Android devices have an accelerometer and a magnetometer sensor inside therefore using a compass app only requires software rather than additional hardware.

As we develop our compass app, we’ll learn setting permissions to use sensors, reading acceleration and magnetic field data in Java code, extracting the orientation data from the sensor data and animating images. In the end, we’ll have a complete compass app that we can use in  daily life.

2.0 List of Materials and Equipment Needed

  • Windows/Mac/Linux Desktop/Laptop
  • Minimum 8GB of RAM and Enough storage to hold all the data
  • Internet Connection
  • JRE (Java runtime environment) installed
  • Android Studio Installed with SDK and Emulator

3.0 Setting up the Required Permissions

Let’s start by creating an Android project first in Android Studio. I named the project as Compass App and selected Empty Activity as the default activity type. The minimum API is also set to 15.

We’ll need a compass image whose needle shows the absolute north. I found the royalty free image shown in Figure 3.1 for this aim (I chose this one because it looks sort of ancient like an ancient compass). You can of course use any other image you like in your project. Please copy and paste this image to your drawable folder as a resource file to use as a UI component. The name of the image is compass.png, we’ll use its name to access it in our code.

        Figure 3.1. The compass Image

If we use sensors in an Android project, we have to get the required permissions to use these sensors in the AndroidManifest.xml file which is located in the manifests folder as shown below:

         Figure 3.2. The AndroidManifest file in the project explorer

Open this file by double clicking on it in Android Studio and you’ll see its default contents as shown in Figure 3.3. Please add the lines shown in Code 3.1 to this file before the <application> tag and you’ll obtain the finalized contents as shown in Code 3.2. These lines make the accelerometer and magnetometer outputs available to be used in our app.

Figure 3.3. Default contents of the AndroidManifest.xml file

                                                           Code 3.1

                                                                        Code 3.2

4.0 Designing the GUI of the App

Now, let’s design the layout of the app. Please open the layout_main.xml file for this and change the text of the default Hello World TextView to Compass App which will serve as the app title. Please set its font size as   30sp and bold style. Then, please position it as follows:

Figure 4.1. The TextView used to display the title of the app

Let’s now place an ImageView in the middle of the GUI and select the compass image that we pasted to the drawable folder:

Figure 4.2. Selecting the compass image for the ImageView component

After we place the ImageView, it’ll be selected. Then, please set up its ID as iv_compass (short for ImageView_compass) from the right pane of Android Studio as follows:

Figure 4.3. Setting the ID of the compass ImageView

Finally, let’s place a TextView below the ImageView in which we’ll display the orientation angle in real time. I set its ID as tv_degrees (short for TextView_degrees), and made it 24sp with a bold text as shown below:

Figure 4.4. Adding the TextView to display the orientation angle

5.0 Writing the Main Code of the App

We completed the design of the user interface and now ready to continue with the coding. Please open the MainActivity.java file in Android Studio. This file will have the default contents as follows:

                                                          Code 5.1


The horizontal direction of a compass bearing is called as azimuth. We’ll calculate this angle from the magnetometer and accelerometer outputs. Let’s define a float  type variable to hold this data:

                                                            Code 5.2

We also need to define objects related to the sensors as follows:

                                                            Code 5.3

In this code, the first object is a SensorManager object that is used to access the sensors. The other two declarations define Sensor objects for  reading the outputs of the accelerometer and the magnetometer.

Finally, let’s declare ImageView and TextView objects which will be used to access the corresponding components in the GUI:

Code 5.4

We can place these declarations inside the MainActivity class just before the onCreate() method. Then, we can assign the default accelerometer and magnetometer sensors to their objects inside the onCreate() method as follows:
 

                                                            Code 5.5

After these declarations and assignments, the MainActivity.java file currently looks like Code 5.6.

Code 5.6


In order to continue with reading sensors, we have to implement SensorEventListener class. We do this by using the implements keyword in the main class definition as follows:

                                                                        Code 5.7

Note that this is a single line code.

When we implement SensorEventListener class, Android Studio warns us by a red bulb saying that we need to implement the required methods in our code:

Figure 5.1. Warning for implementing the required methods

Please click the Implement methods and then Android Studio will automatically place the onSensorChanged() and onSensorActivityChanged() methods when we click the OK button in the dialog box:

Figure 5.2. Dialog showing the methods which will be implemented

Android Studio automatically places the following code to MainActivity.java:

                                                                        Code 5.8

We’ll write our main code inside the onSensorChanged() method. However, before moving on to the main code, let’s write the onResume() and onPause() methods for the main activity because sensors are power hungry components therefore it is important to pause and resume the sensor listeners when the activity pauses and resumes. For this, we simply add the following code just below the end of the onCreate() method:

                                                                        Code 5.9

In the onResume() method, the sensor listeners are registered meaning that the sensors are powered on again when the activity resumes. Similarly, the sensors are unregistered (disconnected) in the onPause() method when the activity pauses.

We’re now ready to write the main code. Firstly, let’s define two float type arrays to hold the accelerometer and magnetometer output data. These will be array variables because the outputs of these sensors are vectoral quantities i.e., they have different values for different directions.

We can define the arrays named accel_read and magnetic_read for these sensors as follows:

Code 5.10

Please write these declarations just before the onSensorChanged() method so that we can access these variables from anywhere in the onSensorChanged() method.

Inside the onSensorChanged() method: This method is called automatically when there’s a new sensor event therefore we’ll write our main code inside this method. The following code creates objects to access the ImageView and TextView of the GUI which will be updated when a sensor event happens:

                                                                        Code 5.11

Then, the following code reads accelerometer and magnetometer sensors and stores the output data to accel_read and magnetic_read arrays:

                                                                        Code 5.12


If the sensor outputs are available (i.e. they are not null), we’ll use the accel_read and magnetic_read variables in the method called getRotationMatrix() to get the rotation matrix R of the device as follows:

                                                                        Code 5.12

If this operation is successful, the successful_read variable will be true and the rotation matrix will be stored in the variable R. In this case, we’re ready to get the azimuth angle (the angle between the device direction and the absolute north) as follows:

                                                                        Code 5.13

In this code:

  • A new array called orientation  is declared.
  • The orientation of the device is extracted using the getOrientation() method and 3-dimensional orientation data is stored in the orientation  array.
  • The first component of this array is the azimuth angle in radians, which is assigned to the azimuth_angle variable in the fourth line.
  • In the fifth line, the azimuth angle in radians is converted to degrees and assigned to the newly created variable degrees.
  • The degrees variable is of float type therefore it is better to round it to an integer. The sixth code line does this job using the method Math.round().
  • Finally, the azimuth angle in integer degrees is shown in the TextView in the user interface. The char 0x00B0 is used to display the degree symbol (°).

It is also good to rotate the compass image according to the azimuth angle. For this animation, we need to declare a float type variable which will hold the current value of the ImageView’s rotation degree:

                                                                        Code 5.14

Then, we can use the following animation code which will rotate the ImageView according to the azimuth angle:

                                                                        Code 5.15

In this code, we declared a RotateAnimate object and then set the animation duration. The startAnimation starts the rotation of the ImageView. This code rotates the compass image in real time according to the degreesInt variable which holds the azimuth angle data.

Combining all these code lines, we reach the following MainActivity.java shown below:

Code 5.16

6.0 Building and Running the App

If we try to run the app in an emulator, the compass will constantly show the north and the azimuth angle as 0 degrees. We need to try this app on a real device with a magnetometer and accelerometer inside (most Android devices have). Please build the app in Android Studio and install it on a real device. I tried this app on Asus Zenfone and it works as expected:

                  Figure 6.1. Compass app running on a real device

7.0 Troubleshooting

For questions or issues related to Android and Android App development, visit https://developer.android.com/studio/troubleshoot or https://developer.android.com for lots of documentation to get help.

8.0 References

  1. https://developer.android.com/index.html
  2. https://www.udacity.com/course/android-development-for-beginners– ud837
  3. http://www.instructables.com/id/How-To-Create-An-Android-App- With-Android-Studio/
  4. Neil Smyth, Android Studio Development Essentials, CreateSpace Independent Publishing Platform, 2016.
  5. Sam Key, Android Programming in a Day, CreateSpace Independent Publishing Platform, 2015.
  6. Barry A. Burd, Android Application Development All-in-One For Dummies, For Dummies, 2015.