Untitled

mail@pastecode.io avatar
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
        }

    }

}