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 SensorDetails(
val sensor: Sensor,
val sensorType: Int,
val axisNames: Array<String>,
val axisSetDetails: Array<AxisSetDetails>
@ -28,7 +29,7 @@ class DolphinSensorEventListener : SensorEventListener {
private val sensorManager: SensorManager?
private val sensorDetails = HashMap<Sensor, SensorDetails>()
private val sensorDetails = ArrayList<SensorDetails>()
private val rotateCoordinatesForScreenOrientation: Boolean
@ -40,6 +41,7 @@ class DolphinSensorEventListener : SensorEventListener {
.getSystemService(Context.SENSOR_SERVICE) as SensorManager?
rotateCoordinatesForScreenOrientation = true
addSensors()
sortSensorDetails()
}
@Keep
@ -58,6 +60,7 @@ class DolphinSensorEventListener : SensorEventListener {
} else {
null
}
sortSensorDetails()
}
private fun addSensors() {
@ -254,15 +257,22 @@ class DolphinSensorEventListener : SensorEventListener {
) {
val sensor = sensorManager!!.getDefaultSensor(sensorType)
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) {
val sensorDetails = sensorDetails[sensorEvent.sensor]
val sensorDetails = sensorDetails.first{s -> sensorsAreEqual(s.sensor, sensorEvent.sensor)}
val values = sensorEvent.values
val axisNames = sensorDetails!!.axisNames
val axisNames = sensorDetails.axisNames
val axisSetDetails = sensorDetails.axisSetDetails
var eventAxisIndex = 0
@ -356,7 +366,7 @@ class DolphinSensorEventListener : SensorEventListener {
}
}
if (!keepSensorAlive) {
setSensorSuspended(sensorEvent.sensor, sensorDetails, true)
setSensorSuspended(sensorDetails, true)
}
}
@ -381,18 +391,14 @@ class DolphinSensorEventListener : SensorEventListener {
*/
@Keep
fun requestUnsuspendSensor(axisName: String) {
for ((key, value) in sensorDetails) {
if (listOf(*value.axisNames).contains(axisName)) {
setSensorSuspended(key, value, false)
for (sd in sensorDetails) {
if (listOf(*sd.axisNames).contains(axisName)) {
setSensorSuspended(sd, false)
}
}
}
private fun setSensorSuspended(
sensor: Sensor,
sensorDetails: SensorDetails,
suspend: Boolean
) {
private fun setSensorSuspended(sensorDetails: SensorDetails, suspend: Boolean) {
var changeOccurred = false
synchronized(sensorDetails) {
@ -404,9 +410,9 @@ class DolphinSensorEventListener : SensorEventListener {
)
if (suspend)
sensorManager!!.unregisterListener(this, sensor)
sensorManager!!.unregisterListener(this, sensorDetails.sensor)
else
sensorManager!!.registerListener(this, sensor, SAMPLING_PERIOD_US)
sensorManager!!.registerListener(this, sensorDetails.sensor, SAMPLING_PERIOD_US)
sensorDetails.isSuspended = suspend
@ -415,14 +421,14 @@ class DolphinSensorEventListener : SensorEventListener {
}
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
fun getAxisNames(): Array<String> {
val axisNames = ArrayList<String>()
for (sensorDetails in sensorDetailsSorted) {
for (sensorDetails in sensorDetails) {
sensorDetails.axisNames.forEach { axisNames.add(it) }
}
return axisNames.toArray(arrayOf())
@ -432,7 +438,7 @@ class DolphinSensorEventListener : SensorEventListener {
fun getNegativeAxes(): BooleanArray {
val negativeAxes = ArrayList<Boolean>()
for (sensorDetails in sensorDetailsSorted) {
for (sensorDetails in sensorDetails) {
var eventAxisIndex = 0
var detailsAxisIndex = 0
var detailsAxisSetIndex = 0
@ -467,22 +473,13 @@ class DolphinSensorEventListener : SensorEventListener {
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 {
// 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
// Set of three axes. Creates a negative companion to each axis.
private const val AXIS_SET_TYPE_OTHER_COORDINATES = 1
private var deviceRotation = Surface.ROTATION_0
// 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) {
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
}
}
}
}