All of the guides to getting compass orientation in Android I\'ve found have a bug: when you hold the phone in portrait mode and \"look\" above the horizon, the compass arrow tu
Error you ask is caused because of Euler angles or called Gimbal Lock.
To solve very high angle difference, you should check if your device is flat or not checking inclination after getting inclination using gravity sensor or getting gravity from accelerometer with lowpass filter. If it's not flat(AR application or inclination>25 || inclination < 155) remap coordinate system from x,y to x,z. That will solve the issue.
SensorManager.getRotationMatrixFromVector(rotationMatrix, event.values);
SensorManager.remapCoordinateSystem(rotationMatrix, SensorManager.AXIS_X, SensorManager.AXIS_Z, remappedRM);
SensorManager.getOrientation(remappedRM, orientation);
This solves the Gimbal Lock, however, 3D compasses(normal compasses does not give correct results due to they are only mapped in x,y and occurs Gimbal Lock) i've seen on Play Store and every code here has a diffence when you keep your device laying flat or screen pointing at you. That difference sometimes gets up to 10 degrees. I haven't able to solve it. Mostly difference is between 1-5 degrees but i sometimes see it rise up to 10 degrees which is not acceptable.
Google measures azimuth from your location. There is a code to find bearing.
currentLocation.getBearing();
Accuracy of lat long(accuracy of your current location) is what determines accuracy of bearing.
List of ways doing a compass with the most accurate to least is in order