Untitled
unknown
kotlin
3 years ago
5.3 kB
4
Indexable
Never
package com.github.nthily.swsclient.components import android.content.Context import android.content.Context.SENSOR_SERVICE import android.hardware.Sensor import android.hardware.SensorEvent import android.hardware.SensorEventListener import android.hardware.SensorManager import android.hardware.SensorManager.SENSOR_DELAY_GAME import androidx.activity.ComponentActivity import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.ViewModel import com.github.nthily.swsclient.viewModel.ConsoleViewModel import java.lang.Exception class SteeringSensor private constructor( context: Context, var onSteeringChanged: ((Float) -> Unit)? = null ) : DefaultLifecycleObserver, SensorEventListener { var started = false private set private val _sensorManager = context.applicationContext.getSystemService( SENSOR_SERVICE) as SensorManager private var _accelerometer: Sensor? = null private var _magnetometer: Sensor? = null private var _gamometer: Sensor? = null private var _supportedSensorLevel = SupportedSensorLevel.NONE private var _gravity = FloatArray(3) private var _geomagnetic = FloatArray(3) private var _rotation = FloatArray(3) private val _matrix = FloatArray(9) private val _orientation = FloatArray(3) init { _accelerometer = _sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) _magnetometer = _sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) _gamometer = _sensorManager.getDefaultSensor(Sensor.TYPE_GAME_ROTATION_VECTOR) if (_gamometer != null) _supportedSensorLevel = SupportedSensorLevel.FULL else if (_accelerometer != null && _magnetometer != null) _supportedSensorLevel = SupportedSensorLevel.MEDIUM else if (_accelerometer != null && _magnetometer == null) _supportedSensorLevel = SupportedSensorLevel.BASIC } fun bind(activity: ComponentActivity) { activity.lifecycle.addObserver(this) } fun start() { if(started) return started = true _start() } fun stop() { if(!started) return started = false _stop() } private fun _start() { _accelerometer?.let { _sensorManager.registerListener(this, it, SENSOR_DELAY_GAME) } _magnetometer?.let { _sensorManager.registerListener(this, it, SENSOR_DELAY_GAME) } _gamometer?.let { _sensorManager.registerListener(this, it, SENSOR_DELAY_GAME) } } private fun _stop() { _sensorManager.unregisterListener(this) } // DefaultLifecycleObserver override fun onCreate(owner: LifecycleOwner) { if(started) _start() } override fun onDestroy(owner: LifecycleOwner) { if(started) _stop() } override fun onResume(owner: LifecycleOwner) { if(started) _start() } override fun onPause(owner: LifecycleOwner) { if(started) _stop() } // SensorEventListener override fun onSensorChanged(event: SensorEvent?) { when (event?.sensor?.type) { Sensor.TYPE_ACCELEROMETER -> _gravity = event.values Sensor.TYPE_MAGNETIC_FIELD -> _geomagnetic = event.values Sensor.TYPE_GAME_ROTATION_VECTOR -> _rotation = event.values } val steering = when (_supportedSensorLevel) { SupportedSensorLevel.BASIC -> { ((1 + (_gravity[1] / SensorManager.STANDARD_GRAVITY)) / 2) } SupportedSensorLevel.MEDIUM -> { SensorManager.getRotationMatrix( _matrix, null, _gravity, _geomagnetic ) SensorManager.getOrientation(_matrix, _orientation) (((Math.PI / 2) - _orientation[1]) / Math.PI).toFloat() } SupportedSensorLevel.FULL -> { SensorManager.getRotationMatrixFromVector(_matrix, _rotation) SensorManager.getOrientation(_matrix, _orientation) (((Math.PI / 2) - _orientation[1]) / Math.PI).toFloat() } else -> 0.5F }.coerceIn(0.0F, 1.0F) try { onSteeringChanged?.invoke(steering) } catch (ex: Exception) { stop() ex.printStackTrace() } } override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { } companion object { @Volatile private var _instance: SteeringSensor? = null fun getInstance(): SteeringSensor? { return _instance } fun getInstance( context: Context, onSteeringChanged: ((Float) -> Unit)? = null ): SteeringSensor { return _instance ?: synchronized(this) { val instance = SteeringSensor(context, onSteeringChanged) _instance = instance instance } } enum class SupportedSensorLevel { NONE, BASIC, MEDIUM, FULL } } }