Sunday, January 9, 2011

Using orientation sensors: Simple Compass sample

In this post we will show how to get the sensor informatión of the device to do a simple compass application.

Getting the magnetic orientation with the TYPE_ORIENTATION sensor is deprecated, and now you must subscribe to TYPE_ACCELEROMETER and TYPE_MAGNETIC_FIELD to get the correct orientation. This way is a little tricky, but with this sample you will get it very easy.

This is the code for an activity that shows in a canvas a simple compass:

package com.samplecompass;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.view.View;

public class CompassActivity extends Activity implements SensorEventListener {

Float azimut; // View to draw a compass

public class CustomDrawableView extends View {
Paint paint = new Paint();
public CustomDrawableView(Context context) {

protected void onDraw(Canvas canvas) {
int width = getWidth();
int height = getHeight();
int centerx = width/2;
int centery = height/2;
canvas.drawLine(centerx, 0, centerx, height, paint);
canvas.drawLine(0, centery, width, centery, paint);
// Rotate the canvas with the azimut
if (azimut != null)
canvas.rotate(-azimut*360/(2*3.14159f), centerx, centery);
canvas.drawLine(centerx, -1000, centerx, +1000, paint);
canvas.drawLine(-1000, centery, 1000, centery, paint);
canvas.drawText("N", centerx+5, centery-10, paint);
canvas.drawText("S", centerx-10, centery+15, paint);

CustomDrawableView mCustomDrawableView;
private SensorManager mSensorManager;
Sensor accelerometer;
Sensor magnetometer;

protected void onCreate(Bundle savedInstanceState) {
mCustomDrawableView = new CustomDrawableView(this);
setContentView(mCustomDrawableView); // Register the sensor listeners
mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
accelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
magnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);

protected void onResume() {
mSensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_UI);
mSensorManager.registerListener(this, magnetometer, SensorManager.SENSOR_DELAY_UI);

protected void onPause() {

public void onAccuracyChanged(Sensor sensor, int accuracy) { }

float[] mGravity;
float[] mGeomagnetic;
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
mGravity = event.values;
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
mGeomagnetic = event.values;
if (mGravity != null && mGeomagnetic != null) {
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I, mGravity, mGeomagnetic);
if (success) {
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
azimut = orientation[0]; // orientation contains: azimut, pitch and roll

I hope It will be useful for you.

Note: This is real code from Trackeen: your Mushrooms and Fishing GPS.


  1. Hi,
    I just try this code and it don't work...
    It need any special permission in the manifest?
    or any special code in the main.xml?

  2. Yes you needn both or one of the following permissions:


  3. thank you for this nice example.
    i have been tried many times but every time i faced failure thank you...
    keep this help up for beginners ..

  4. Thanks to you, for commenting the post.

    And remember, everyone is a beginner at some time.

  5. Thank you for this great post.. I wanted to know how I could modify this code to get true North azimut as opposed to Magnetic North. Again thanks for this great post...


    1. Hope it helps :)

      GeomagneticField geoField = new GeomagneticField(

      azimuth -= geoField.getDeclination(); // converts magnetic north into true north

  6. Hello Orlando,

    The difference between Geographic and Magnetic Norths, varies both from place to place, and with the passage of time. Yo must get the Magnetic Declination, witch is the difference between both.

    There are tables to get the magnetic declination in base of latitude and longitude and time, but I never used them.

  7. Nice, great post.
    I have made a similar compass app with map display and bearings as well and released the code OS.
    Check my blog @

  8. Sir i have created a screen from xml when I changes the orientation of mobile the buttons position are getting changed...can you tell me a better way to create screen that doesnot change the position of those buttons.....for example i created four buttons at the bottom of the screen ,when I changed the position of the screen to landscape the positon are changing .....

  9. Hi,
    What happens if I work with 5 Sensors? do I need to create a type of "Switch case" to check which sensor triggered the event? (you did "if" for 2)
    Or maybe it is possible to create different event handlers to each sensor type, and then the performance will be better?
    Thank you,

  10. not use <uses-permission..... in my htc Wildfire
    in Android 2.3.3

  11. Thank you very much this helped me a lot.

    A small hint:
    If you want to have azimut in degrees, there's a simple Math-function for it Math.toDegrees(azimut)
    This will give you something between -180° and 180°.

  12. I made a radar simulator some time ago using TYPE_ORIENTATION sensor. I tried updating my implementation with this new way, but the results are not as smooth as before. Targets get a little shaky now. Any ideas of why this could be happening?

    1. i have the same problem when my Math.abs(orientation[1]) bigger than 80 =((( orientation[2] starts shaking... have no idea how to fix that problem.. TYPE_ORIENTATION was really amazing but Google Dev deprecated it -_-

  13. @Androideas I have the same problem with the readings of Azimuth.
    It is not smooth at all. Besides, the values are not accurate. I am talking about 30-40 degrees of error. Does any one know who to compensate that error?

    1. I had the same problem and solved it with these changes:

      Line 78: mGravity = event.values;
      Replaced: mGravity = event.values.clone();

      Line 80: mGeomagnetic = event.values;
      Replaced: mGeomagnetic = event.values.clone();

    2. Dors not works for me, still shaking

  14. this is such a nice example. it will working fine in 2.3 but will it work in 4.0?

  15. I've been doing this onSensorChanged and it seems to work so far. Why did you choose to do this onAccuracyChanged?

    1. it's on onSensorChanged. Look again, probably an optical illusion..

    2. Indeed it is an optical illusion :)
      it got me too, because I didn't notice the closing curly brace of onAccuracyChanged

  16. My test compass app worked on a Kindle Fire using TYPE_ORIENTATION. When I tried the new code I discovered that the Kindle returns null for sensor TYPE_MAGNETIC_FIELD. Yet it was able to provide a compass bearing using the deprecated method. To work on more devices the code apparently needs to try other sensors.

    1. @Joe Mattioni did you find a solution? I Try it using a samsung galaxy tab 7.7" P6800 and it shows nothing...

  17. My old test app using TYPE_ORIENTATION update orientation value about 30~40 ms
    (I register listener in SENSOR_DELAY_FASTEST mode).

    But when I use this new solution to avoid deprecation,
    my test app update orientation value about 2~3 s.
    It's so lated
    Is there any solution about increasing orientation sensor updated rate and also avoiding deprecation?

  18. Use SENSOR_DELAY_GAME, it is faster for me than SENSOR_DELAY_FASTEST... For shake readings use low pass filter :)

  19. Thank you so much for this, it's really helpful and exactly what I needed. Was stuck on getting orientation for the longest time before I found this.

  20. It seems that no one had faced a similar problem with me. SensorManager.getRotationMatrix(...) method returns false nearly all the time.

  21. With this example north just turns with the device and doesn't stay pointed north, it just kind of lags around. Anyone have this problem?

  22. Hi,
    You've one serious bug

    mGravity = event.values;
    mGeomagnetic = event.values;

    Here you should copy data, otherwise mGravity could be equal to mGeomagnetic , because they are just references!

    1. it takes different values for each event...

  23. Hi,
    I am developing a compass app for some other platform. Problem is i have only raw magnetometer reading and accelerometer readings. Can you tell me how can i use these reading to calculate magnetic heading for the app.
    Any help will be appreciated. Thank you.

  24. Thanks for sharing! This is not towards you or your code, but the depricated way gives me a much more "stable" result, the new way makes my compass flicker 0.5 degrees back and forward. Sure I can code around that problem, but why did the android devs do that in first place?

  25. Thanks for your nice codes .
    But what are the green lines for ??
    what do they represent ??
    the app works fine for me but it doesn't show the directions correctly
    should I keep my phone in a specific orientation to get the correct directions of south and north or it should work fine in any orientations of the phone ?...

  26. why orientation[2] jumps really bad (for example -174 and next second +174) when orientation[0] >=80? How can i fix this problem??? I had no problem with TYPE_ORIENTATION. BUT they marked it as deprecated =(! Why???

  27. Thank You for the tutorial. I tryed using the same logic but the rotation shows an error of around 40 to 45 degrees.

  28. why do you use a negative value for canvas rotation

  29. This has helped me tremendously. THANK YOU