1
0
mirror of https://git.sr.ht/~thestr4ng3r/chiaki synced 2025-03-12 05:25:23 -07:00

Add Motion to Android

This commit is contained in:
Florian Märkl 2021-01-12 21:08:33 +01:00
parent 2a4b67b58e
commit 2906cfdd69
No known key found for this signature in database
GPG Key ID: 125BC8A5A6A1E857
3 changed files with 95 additions and 13 deletions
android/app/src/main/java/com/metallic/chiaki

@ -1,19 +1,36 @@
package com.metallic.chiaki.session
import android.util.Log
import android.view.InputDevice
import android.view.KeyEvent
import android.view.MotionEvent
import android.content.Context
import android.hardware.*
import android.view.*
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.OnLifecycleEvent
import com.metallic.chiaki.common.Preferences
import com.metallic.chiaki.lib.ControllerState
class StreamInput(val preferences: Preferences)
class StreamInput(val context: Context, val preferences: Preferences)
{
var controllerStateChangedCallback: ((ControllerState) -> Unit)? = null
val controllerState: ControllerState get()
{
val controllerState = keyControllerState or motionControllerState
val controllerState = sensorControllerState or keyControllerState or motionControllerState
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
when(windowManager.defaultDisplay.rotation)
{
Surface.ROTATION_90 -> {
controllerState.accelX *= -1.0f
controllerState.accelZ *= -1.0f
controllerState.gyroX *= -1.0f
controllerState.gyroZ *= -1.0f
controllerState.orientX *= -1.0f
controllerState.orientZ *= -1.0f
}
else -> {}
}
// prioritize motion controller's l2 and r2 over key
// (some controllers send only key, others both but key earlier than full press)
@ -25,6 +42,7 @@ class StreamInput(val preferences: Preferences)
return controllerState or touchControllerState
}
private val sensorControllerState = ControllerState() // from Motion Sensors
private val keyControllerState = ControllerState() // from KeyEvents
private val motionControllerState = ControllerState() // from MotionEvents
var touchControllerState = ControllerState()
@ -36,6 +54,65 @@ class StreamInput(val preferences: Preferences)
private val swapCrossMoon = preferences.swapCrossMoon
private val sensorEventListener = object: SensorEventListener {
override fun onSensorChanged(event: SensorEvent)
{
when(event.sensor.type)
{
Sensor.TYPE_ACCELEROMETER -> {
sensorControllerState.accelX = event.values[1] / SensorManager.GRAVITY_EARTH
sensorControllerState.accelY = event.values[2] / SensorManager.GRAVITY_EARTH
sensorControllerState.accelZ = event.values[0] / SensorManager.GRAVITY_EARTH
}
Sensor.TYPE_GYROSCOPE -> {
sensorControllerState.gyroX = event.values[1]
sensorControllerState.gyroY = event.values[2]
sensorControllerState.gyroZ = event.values[0]
}
Sensor.TYPE_ROTATION_VECTOR -> {
val q = floatArrayOf(0f, 0f, 0f, 0f)
SensorManager.getQuaternionFromVector(q, event.values)
sensorControllerState.orientX = q[2]
sensorControllerState.orientY = q[3]
sensorControllerState.orientZ = q[1]
sensorControllerState.orientW = q[0]
}
else -> return
}
controllerStateUpdated()
}
override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {}
}
private val lifecycleObserver = object: LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun onResume()
{
val samplingPeriodUs = 4000
val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
listOfNotNull(
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE),
sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR)
).forEach {
sensorManager.registerListener(sensorEventListener, it, samplingPeriodUs)
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun onPause()
{
val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
sensorManager.unregisterListener(sensorEventListener)
}
}
fun observe(lifecycleOwner: LifecycleOwner)
{
lifecycleOwner.lifecycle.addObserver(lifecycleObserver)
}
private fun controllerStateUpdated()
{
controllerStateChangedCallback?.let { it(controllerState) }

@ -5,6 +5,7 @@ package com.metallic.chiaki.stream
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.app.AlertDialog
import android.content.res.Configuration
import android.graphics.Matrix
import android.os.Bundle
import android.os.Handler
@ -58,9 +59,11 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe
}
viewModel = ViewModelProvider(this, viewModelFactory {
StreamViewModel(Preferences(this), LogManager(this), connectInfo)
StreamViewModel(application, connectInfo)
})[StreamViewModel::class.java]
viewModel.input.observe(this)
setContentView(R.layout.activity_stream)
window.decorView.setOnSystemUiVisibilityChangeListener(this)
@ -305,7 +308,6 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe
override fun dispatchKeyEvent(event: KeyEvent) = viewModel.input.dispatchKeyEvent(event) || super.dispatchKeyEvent(event)
override fun onGenericMotionEvent(event: MotionEvent) = viewModel.input.onGenericMotionEvent(event) || super.onGenericMotionEvent(event)
}

@ -2,19 +2,22 @@
package com.metallic.chiaki.stream
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import android.app.Application
import android.content.Context
import androidx.lifecycle.*
import com.metallic.chiaki.common.LogManager
import com.metallic.chiaki.session.StreamSession
import com.metallic.chiaki.common.Preferences
import com.metallic.chiaki.lib.*
import com.metallic.chiaki.session.StreamInput
class StreamViewModel(val preferences: Preferences, val logManager: LogManager, val connectInfo: ConnectInfo): ViewModel()
class StreamViewModel(val application: Application, val connectInfo: ConnectInfo): ViewModel()
{
val preferences = Preferences(application)
val logManager = LogManager(application)
private var _session: StreamSession? = null
val input = StreamInput(preferences)
val input = StreamInput(application, preferences)
val session = StreamSession(connectInfo, logManager, preferences.logVerbose, input)
private var _onScreenControlsEnabled = MutableLiveData<Boolean>(preferences.onScreenControlsEnabled)