This video shows the steps to develop your own custom compass App which can be used to get the direction North, South, East and West.
It uses the Magnetic Field and Accelerometer sensor to get the orientation of the phone. Using the values from the getOrientation method, it fetches Azimuth, the angular value from the Magnetic north.
To get the rotation matrix, an input required by the getOrientation method, getRotationMatrix mathod is used. This getRotationMatrix method needs the Magnetic Field and Accelerometer sensor values to compute the rotation matrix.
Details on getOrientation and getRotationMAtrix can be found at below Android developer portal links:
Finally, to display the output a pointer image is used in the ImageView widget. This pointer is rotated as per the Azimuth values received from the getOrientation method.
For any suggestions, comments, questions or appreciation, we will be glad to hear from you at: https://programmerworld.co/contact/ or programmerworld1990@gmail.com
Image file used:
Application layout screenshot as tested on a real phone:
Complete Source code:
Java code
package com.example.mycompassapp; import androidx.appcompat.app.AppCompatActivity; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Bundle; import android.view.View; import android.widget.ImageView; public class MainActivity extends AppCompatActivity { private ImageView imageView; private SensorManager sensorManager; private Sensor sensorAccelerometer; private Sensor sensorMagneticField; private float[] floatGravity = new float[3]; private float[] floatGeoMagnetic = new float[3]; private float[] floatOrientation = new float[3]; private float[] floatRotationMatrix = new float[9]; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView = findViewById(R.id.imageView); sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); sensorAccelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); sensorMagneticField = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); SensorEventListener sensorEventListenerAccelrometer = new SensorEventListener() { @Override public void onSensorChanged(SensorEvent event) { floatGravity = event.values; SensorManager.getRotationMatrix(floatRotationMatrix, null, floatGravity, floatGeoMagnetic); SensorManager.getOrientation(floatRotationMatrix, floatOrientation); imageView.setRotation((float) (-floatOrientation[0]*180/3.14159)); } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } }; SensorEventListener sensorEventListenerMagneticField = new SensorEventListener() { @Override public void onSensorChanged(SensorEvent event) { floatGeoMagnetic = event.values; SensorManager.getRotationMatrix(floatRotationMatrix, null, floatGravity, floatGeoMagnetic); SensorManager.getOrientation(floatRotationMatrix, floatOrientation); imageView.setRotation((float) (-floatOrientation[0]*180/3.14159)); } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } }; sensorManager.registerListener(sensorEventListenerAccelrometer, sensorAccelerometer, SensorManager.SENSOR_DELAY_NORMAL); sensorManager.registerListener(sensorEventListenerMagneticField, sensorMagneticField, SensorManager.SENSOR_DELAY_NORMAL); } public void ResetButton(View view){ imageView.setRotation(180); } }
Layout XML file
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <ImageView android:id="@+id/imageView" android:layout_width="271dp" android:layout_height="412dp" android:layout_marginStart="70dp" android:layout_marginTop="49dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:srcCompat="@drawable/pointer" android:contentDescription="@string/todo" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="160dp" android:layout_marginTop="28dp" android:onClick="ResetButton" android:text="@string/reset" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/imageView" /> </androidx.constraintlayout.widget.ConstraintLayout>
Manifest File
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.mycompassapp"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>