Android: Use structural equality for sensorDetails

To fix the crash in input device sensor handling, we should look up
Sensors using structural equality. Unfortunately, Sensor.equals
implements referential equality, and HashMap doesn't let us provide a
custom comparator. Because the number of sensors is relatively small,
and because we have a reason to keep a sorted list of sensors around
anyway, let's switch from HashMap to ArrayList.
This commit is contained in:
JosJuice 2024-07-20 21:06:07 +02:00
parent 87b7009c12
commit 7b0a7f15b0
1 changed files with 33 additions and 28 deletions

View File

@ -19,6 +19,7 @@ class DolphinSensorEventListener : SensorEventListener {
private class AxisSetDetails(val firstAxisOfSet: Int, val axisSetType: Int) private class AxisSetDetails(val firstAxisOfSet: Int, val axisSetType: Int)
private class SensorDetails( private class SensorDetails(
val sensor: Sensor,
val sensorType: Int, val sensorType: Int,
val axisNames: Array<String>, val axisNames: Array<String>,
val axisSetDetails: Array<AxisSetDetails> val axisSetDetails: Array<AxisSetDetails>
@ -28,7 +29,7 @@ class DolphinSensorEventListener : SensorEventListener {
private val sensorManager: SensorManager? private val sensorManager: SensorManager?
private val sensorDetails = HashMap<Sensor, SensorDetails>() private val sensorDetails = ArrayList<SensorDetails>()
private val rotateCoordinatesForScreenOrientation: Boolean private val rotateCoordinatesForScreenOrientation: Boolean
@ -40,6 +41,7 @@ class DolphinSensorEventListener : SensorEventListener {
.getSystemService(Context.SENSOR_SERVICE) as SensorManager? .getSystemService(Context.SENSOR_SERVICE) as SensorManager?
rotateCoordinatesForScreenOrientation = true rotateCoordinatesForScreenOrientation = true
addSensors() addSensors()
sortSensorDetails()
} }
@Keep @Keep
@ -58,6 +60,7 @@ class DolphinSensorEventListener : SensorEventListener {
} else { } else {
null null
} }
sortSensorDetails()
} }
private fun addSensors() { private fun addSensors() {
@ -254,15 +257,22 @@ class DolphinSensorEventListener : SensorEventListener {
) { ) {
val sensor = sensorManager!!.getDefaultSensor(sensorType) val sensor = sensorManager!!.getDefaultSensor(sensorType)
if (sensor != null) { if (sensor != null) {
sensorDetails[sensor] = SensorDetails(sensorType, axisNames, axisSetDetails) sensorDetails.add(SensorDetails(sensor, sensorType, axisNames, axisSetDetails))
} }
} }
private fun sortSensorDetails() {
Collections.sort(
sensorDetails,
Comparator.comparingInt { s: SensorDetails -> s.sensorType }
)
}
override fun onSensorChanged(sensorEvent: SensorEvent) { override fun onSensorChanged(sensorEvent: SensorEvent) {
val sensorDetails = sensorDetails[sensorEvent.sensor] val sensorDetails = sensorDetails.first{s -> sensorsAreEqual(s.sensor, sensorEvent.sensor)}
val values = sensorEvent.values val values = sensorEvent.values
val axisNames = sensorDetails!!.axisNames val axisNames = sensorDetails.axisNames
val axisSetDetails = sensorDetails.axisSetDetails val axisSetDetails = sensorDetails.axisSetDetails
var eventAxisIndex = 0 var eventAxisIndex = 0
@ -356,7 +366,7 @@ class DolphinSensorEventListener : SensorEventListener {
} }
} }
if (!keepSensorAlive) { if (!keepSensorAlive) {
setSensorSuspended(sensorEvent.sensor, sensorDetails, true) setSensorSuspended(sensorDetails, true)
} }
} }
@ -381,18 +391,14 @@ class DolphinSensorEventListener : SensorEventListener {
*/ */
@Keep @Keep
fun requestUnsuspendSensor(axisName: String) { fun requestUnsuspendSensor(axisName: String) {
for ((key, value) in sensorDetails) { for (sd in sensorDetails) {
if (listOf(*value.axisNames).contains(axisName)) { if (listOf(*sd.axisNames).contains(axisName)) {
setSensorSuspended(key, value, false) setSensorSuspended(sd, false)
} }
} }
} }
private fun setSensorSuspended( private fun setSensorSuspended(sensorDetails: SensorDetails, suspend: Boolean) {
sensor: Sensor,
sensorDetails: SensorDetails,
suspend: Boolean
) {
var changeOccurred = false var changeOccurred = false
synchronized(sensorDetails) { synchronized(sensorDetails) {
@ -404,9 +410,9 @@ class DolphinSensorEventListener : SensorEventListener {
) )
if (suspend) if (suspend)
sensorManager!!.unregisterListener(this, sensor) sensorManager!!.unregisterListener(this, sensorDetails.sensor)
else else
sensorManager!!.registerListener(this, sensor, SAMPLING_PERIOD_US) sensorManager!!.registerListener(this, sensorDetails.sensor, SAMPLING_PERIOD_US)
sensorDetails.isSuspended = suspend sensorDetails.isSuspended = suspend
@ -415,14 +421,14 @@ class DolphinSensorEventListener : SensorEventListener {
} }
if (changeOccurred) { if (changeOccurred) {
Log.info((if (suspend) "Suspended sensor " else "Unsuspended sensor ") + sensor.name) Log.info((if (suspend) "Suspended sensor " else "Unsuspended sensor ") + sensorDetails.sensor.name)
} }
} }
@Keep @Keep
fun getAxisNames(): Array<String> { fun getAxisNames(): Array<String> {
val axisNames = ArrayList<String>() val axisNames = ArrayList<String>()
for (sensorDetails in sensorDetailsSorted) { for (sensorDetails in sensorDetails) {
sensorDetails.axisNames.forEach { axisNames.add(it) } sensorDetails.axisNames.forEach { axisNames.add(it) }
} }
return axisNames.toArray(arrayOf()) return axisNames.toArray(arrayOf())
@ -432,7 +438,7 @@ class DolphinSensorEventListener : SensorEventListener {
fun getNegativeAxes(): BooleanArray { fun getNegativeAxes(): BooleanArray {
val negativeAxes = ArrayList<Boolean>() val negativeAxes = ArrayList<Boolean>()
for (sensorDetails in sensorDetailsSorted) { for (sensorDetails in sensorDetails) {
var eventAxisIndex = 0 var eventAxisIndex = 0
var detailsAxisIndex = 0 var detailsAxisIndex = 0
var detailsAxisSetIndex = 0 var detailsAxisSetIndex = 0
@ -467,22 +473,13 @@ class DolphinSensorEventListener : SensorEventListener {
return result return result
} }
private val sensorDetailsSorted: List<SensorDetails>
get() {
val sensorDetails = ArrayList(sensorDetails.values)
Collections.sort(
sensorDetails,
Comparator.comparingInt { s: SensorDetails -> s.sensorType }
)
return sensorDetails
}
companion object { companion object {
// Set of three axes. Creates a negative companion to each axis, and corrects for device rotation. // Set of three axes. Creates a negative companion to each axis, and corrects for device rotation.
private const val AXIS_SET_TYPE_DEVICE_COORDINATES = 0 private const val AXIS_SET_TYPE_DEVICE_COORDINATES = 0
// Set of three axes. Creates a negative companion to each axis. // Set of three axes. Creates a negative companion to each axis.
private const val AXIS_SET_TYPE_OTHER_COORDINATES = 1 private const val AXIS_SET_TYPE_OTHER_COORDINATES = 1
private var deviceRotation = Surface.ROTATION_0 private var deviceRotation = Surface.ROTATION_0
// The fastest sampling rate Android lets us use without declaring the HIGH_SAMPLING_RATE_SENSORS // The fastest sampling rate Android lets us use without declaring the HIGH_SAMPLING_RATE_SENSORS
@ -500,5 +497,13 @@ class DolphinSensorEventListener : SensorEventListener {
fun setDeviceRotation(deviceRotation: Int) { fun setDeviceRotation(deviceRotation: Int) {
this.deviceRotation = deviceRotation this.deviceRotation = deviceRotation
} }
private fun sensorsAreEqual(s1: Sensor, s2: Sensor): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && s1.id > 0 && s2.id > 0) {
s1.type == s2.type && s1.id == s2.id
} else {
s1.type == s2.type && s1.name == s2.name
}
}
} }
} }