Get device angle by using getOrientation() function
Asked Answered
S

4

18

I was using Sensor.TYPE_ORIENTATION to determine current angle of device but TYPE_ORIENTATION is deprecated on API version 8. In SensorManager manual it refers to getOrientation() function in order to use TYPE_ORIENTATION.

Here is the manual


Here is my old code :

public void onSensorChanged(SensorEvent event) {
        Log.d("debug","Sensor Changed");
        if (event.sensor.getType()==Sensor.TYPE_ORIENTATION) {
            Log.d("debug",Float.toString(event.values[0]));


            float mAzimuth = event.values[0];
            float mPitch = event.values[1];
            float mRoll = event.values[2];

            Log.d("debug","mAzimuth :"+Float.toString(mAzimuth));
            Log.d("debug","mPitch :"+Float.toString(mPitch));
            Log.d("debug","mRoll :"+Float.toString(mRoll));
        }

    }

I'm really confused about using getOrientation() function, can anyone please show me an example how to get the angles?

Schiro answered 2/12, 2013 at 23:25 Comment(0)
E
37

You now use two sensors (ACCELEROMETER and MAGNETIC_FIELD) to get that information. See blog post for more detail.

public class CompassActivity extends Activity implements SensorEventListener {

  private SensorManager mSensorManager;
  Sensor accelerometer;
  Sensor magnetometer;

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    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() {
    super.onResume();
    mSensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_UI);
    mSensorManager.registerListener(this, magnetometer, SensorManager.SENSOR_DELAY_UI);
  }

  protected void onPause() {
    super.onPause();
    mSensorManager.unregisterListener(this);
  }

  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
      }
    }
  }
}

Permissions:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
Enosis answered 2/12, 2013 at 23:45 Comment(7)
Thanks for the response, but the line below always returns false : boolean success = SensorManager.getRotationMatrix(R, I, mGravity, mGeomagnetic);Schiro
Weird but check out https://mcmap.net/q/669476/-android-why-getrotationmatrix-return-false seems like looping through the event values instead of a direct reference might fix it.Enosis
No, it is not returning false always, it returns true sometimes, approximately returns true every 10 seconds, but timing is not regular.Schiro
Sounds like a new question, sorry.Enosis
@Schiro it returns false because most likely your device has no compass and hence you don't get magnetic values.Vtol
WARNING: the code above will garbage collect A LOT because of the new arrays within onSensorChanged(). The code here is better: https://mcmap.net/q/669477/-what-is-the-alternative-to-android-orientation-sensorOrganicism
It might be good to update this also now to point towards the 'Sensor.TYPE_ROTATION_VECTOR ' which is likely widely supported and can be much easier to use - good example here to steer people to https://mcmap.net/q/669478/-azimuth-reading-changes-to-opposite-when-user-holds-the-phone-uprightSuprematism
C
4

Regarding your second question. When you are registering your sensor listeners, change your code to read:

protected void onResume() {          
    super.onResume();          
    mSensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL);          
    mSensorManager.registerListener(this, magnetometer, SensorManager.SENSOR_DELAY_NORMAL);          
}
Chemisette answered 23/12, 2014 at 18:11 Comment(0)
A
1

Google has a great demo app for orientation in their google-developer-training series called TiltSpot. Because it has an Apache license, I've taken the liberty of turning it into a small library called johnnylambada-orientation that makes getting orientation as simple adding this to your activity:

        getLifecycle().addObserver(new OrientationReporter(this, (a, p, r) -> {
            Log.i("orientation","a="+a+" p="+p+" r="+r);
        }));
Amphipod answered 20/12, 2019 at 0:55 Comment(1)
Failed to resolve: com.github.johnnylambada:johnnylambada-orientation:1.0.0Complect
B
1

My Answer is for those who getting jumping values of heading. For further instruction let me know in the comment.

Sensor accelerometer;
Sensor magnetometer;
private float[] mGravity = new float[3];
private float[] mGeomagnetic = new float[3];
private float[] Rv = new float[9];
private float[] I = new float[9]; 

class MapsActivity

public class MapsActivity extends FragmentActivity implements OnMapReadyCallback, SensorEventListener{

onSensorChanged(SensorEvent event)

@Override
public void onSensorChanged(SensorEvent event) {

    synchronized (this) {
        float INITIAL_ALPHA = 0.97f;
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {

            mGravity[0] = INITIAL_ALPHA * mGravity[0] + (1 - INITIAL_ALPHA)
                    * event.values[0];
            mGravity[1] = INITIAL_ALPHA * mGravity[1] + (1 - INITIAL_ALPHA)
                    * event.values[1];
            mGravity[2] = INITIAL_ALPHA * mGravity[2] + (1 - INITIAL_ALPHA)
                    * event.values[2];
        }
        if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {

            mGeomagnetic[0] = INITIAL_ALPHA * mGeomagnetic[0] + (1 - INITIAL_ALPHA)
                    * event.values[0];
            mGeomagnetic[1] = INITIAL_ALPHA * mGeomagnetic[1] + (1 - INITIAL_ALPHA)
                    * event.values[1];
            mGeomagnetic[2] = INITIAL_ALPHA * mGeomagnetic[2] + (1 - INITIAL_ALPHA)
                    * event.values[2];

            if (Math.abs(mGeomagnetic[2]) > Math.abs(mGeomagnetic[1])) {
                magStrength = Math.round(Math.abs(mGeomagnetic[2]));
            } else {
                magStrength = Math.round(Math.abs(mGeomagnetic[1]));
            }
        }

        boolean success = SensorManager.getRotationMatrix(Rv, I, mGravity, mGeomagnetic);
        if (success) {
            float[] orientation = new float[3];
            SensorManager.getOrientation(Rv, orientation);

            azimuth = (float) Math.toDegrees(orientation[0]);
            azimuth = (azimuth + 360) % 360;
            // Log.d(TAG, "azimuth (deg): " + azimuth);

            float degree = Math.round(azimuth);

            // create a rotation animation (reverse turn degree degrees)
            RotateAnimation ra = new RotateAnimation(
                    currentDegree,
                    -degree,
                    Animation.RELATIVE_TO_SELF, 0.5f,
                    Animation.RELATIVE_TO_SELF,
                    0.5f);

            ra.setDuration(500);
            ra.setFillAfter(true);
            ra.setRepeatCount(0);

            binding.compassImage.startAnimation(ra);
            showDirection(degree);

            currentDegree = -degree;

        }
    }
}

onAccuracyChanged

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {

}

onResume()

 @Override
protected void onResume() {
    super.onResume();
    if (mSensorManager == null) {
        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        accelerometer = 
       mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        magnetometer = 
       mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
    }
       mSensorManager.registerListener(this, accelerometer, 
       SensorManager.SENSOR_DELAY_UI);
       mSensorManager.registerListener(this, magnetometer, 
       SensorManager.SENSOR_DELAY_UI);
}

onPause()

@Override
protected void onPause() {
    super.onPause();
    mSensorManager.unregisterListener(MapsActivity.this);
}
Broadbent answered 29/6, 2021 at 5:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.