I’m working on an Android application that requires accurate orientation heading updates using the FusedOrientationProviderClient and a custom DeviceOrientationListener. However, I’m experiencing issues with orientation accuracy and incorrect heading values, especially when the device is flat on a surface.
-
When the device is not flat it’s showing almost every time the right heading.
-
If the first value is not accurate,its not fixing itself to the right heading,its just keep updating the wrong heading.
Here’s the class I am using for orientation updates:
class LocationOrientationRepo(context: Context) {
private var deviceOrientationListener: DeviceOrientationListenerImpl? = null
private val fusedOrientationProviderClient: FusedOrientationProviderClient =
LocationServices.getFusedOrientationProviderClient(context)
private val handler = Handler(Looper.getMainLooper())
private val refreshRunnable = object : Runnable {
override fun run() {
checkOrientationListener()
handler.postDelayed(this, REFRESH_INTERVAL_MS)
}
}
private var lastAzimuth: Float? = null
private val threshold = 0.0f // Set your threshold value (in degrees)
fun startListening(onOrientationChanged: (Float) -> Unit) {
if (deviceOrientationListener == null) {
deviceOrientationListener = DeviceOrientationListenerImpl { azimuth ->
if (shouldNotify(azimuth)) {
lastAzimuth = azimuth
onOrientationChanged(azimuth)
}
}
val request = DeviceOrientationRequest.Builder(DeviceOrientationRequest.OUTPUT_PERIOD_DEFAULT).build()
val executor: ExecutorService = Executors.newSingleThreadExecutor()
fusedOrientationProviderClient.requestOrientationUpdates(request, executor, deviceOrientationListener!!)
.addOnSuccessListener {
Log.i(TAG, "Successfully added new orientation listener")
handler.post(refreshRunnable)
}
.addOnFailureListener { e ->
Log.e(TAG, "Failed to add new orientation listener", e)
}
}
}
fun stopListening() {
if (deviceOrientationListener != null) {
Log.i(TAG, "Removing active orientation listener")
fusedOrientationProviderClient.removeOrientationUpdates(deviceOrientationListener!!)
deviceOrientationListener = null
handler.removeCallbacks(refreshRunnable)
}
}
private fun checkOrientationListener() {
if (deviceOrientationListener == null) {
Log.i(TAG, "Orientation listener not active. Restarting.")
startListening { azimuth ->
Log.d(TAG, "Orientation callback with azimuth: $azimuth")
}
}
}
private fun shouldNotify(newAzimuth: Float): Boolean {
// If lastAzimuth is null, initialize it
if (lastAzimuth == null) {
lastAzimuth = newAzimuth
return true
}
// Calculate the difference
val diff = Math.abs(newAzimuth - (lastAzimuth ?: newAzimuth))
return diff >= threshold
}
private inner class DeviceOrientationListenerImpl(private val onOrientationChanged: (Float) -> Unit) :
DeviceOrientationListener {
override fun onDeviceOrientationChanged(deviceOrientation: DeviceOrientation) {
val azimuth = deviceOrientation.headingDegrees
Log.d(TAG, "Device Orientation Changed - Heading: $azimuth") // Debug log for azimuth
onOrientationChanged(azimuth)
}
}
companion object {
private const val TAG = "LocationOrientationRepo"
private const val REFRESH_INTERVAL_MS = 10000L // 10 seconds
}
}
Issue:
- Inaccuracy of Orientation Heading:
The heading direction provided by DeviceOrientationListener is not always accurate.
When the device is flat, the heading direction seems incorrect and does not update properly.
- Sensor Event Issues:
Using sensor events directly also yields inaccurate and erratic results, especially when rotating the device.
What I’ve Tried:
I’ve tried using sensors events but they produce unstable and incorrect values when the device is rotated.
Questions:
- How can I improve the accuracy of the orientation heading?
- How can I handle orientation updates correctly when the device is flat?
- Would you use a different method?
Any guidance or suggestions on how to fix these issues would be greatly appreciated.
Thank you !