Extracted sensor listening logic from PolarFragment.kt to Orientation.kt

This commit is contained in:
Arty Bishop committed 2021-04-03 17:22:01 +01:00
1 parent c2216e4917
commit 8c67ec4808
3 files changed
+130 -86

No files matched your search

@@ -20,7 +20,9 @@ package com.rtbishop.look4sat.di
import android.content.ContentResolver
import android.content.Context
import android.content.SharedPreferences
import android.hardware.SensorManager
import android.location.LocationManager
import android.view.WindowManager
import androidx.preference.PreferenceManager
import dagger.Module
import dagger.Provides
@@ -42,6 +44,16 @@ object ApplicationModule {
return context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
}
@Provides
fun provideSensorManager(@ApplicationContext context: Context): SensorManager {
return context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
}
@Provides
fun provideWindowManager(@ApplicationContext context: Context): WindowManager {
return context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
}
@Provides
fun provideSharedPreferences(@ApplicationContext context: Context): SharedPreferences {
return PreferenceManager.getDefaultSharedPreferences(context)
@@ -0,0 +1,94 @@
/*
* Look4Sat. Amateur radio satellite tracker and pass predictor.
* Copyright (C) 2019-2021 Arty Bishop (bishop.arty@gmail.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.rtbishop.look4sat.ui.polarScreen
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import android.view.Surface
import android.view.WindowManager
import javax.inject.Inject
import kotlin.math.atan2
import kotlin.math.round
class Orientation @Inject constructor(
private val mSensorManager: SensorManager,
private val mWindowManager: WindowManager
) : SensorEventListener {
interface OrientationListener {
fun onOrientationChanged(azimuth: Float, pitch: Float, roll: Float)
}
private val mRotationSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR)
private val mRotationMatrix = FloatArray(9)
private val mOrientationValues = FloatArray(3)
private val mOneRadDegrees = 57.295779513f
private var mLastAccuracy: Int = SensorManager.SENSOR_STATUS_UNRELIABLE
private var mListener: OrientationListener? = null
fun startListening(listener: OrientationListener) {
when {
mListener === listener -> return
else -> {
mListener = listener
mSensorManager.registerListener(this, mRotationSensor, 16000)
}
}
}
fun stopListening() {
mSensorManager.unregisterListener(this)
mListener = null
}
override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
mLastAccuracy = accuracy
}
override fun onSensorChanged(event: SensorEvent) {
when {
mListener == null -> return
mLastAccuracy == SensorManager.SENSOR_STATUS_UNRELIABLE -> return
event.sensor == mRotationSensor -> updateOrientation(event.values)
}
}
@Suppress("DEPRECATION")
private fun updateOrientation(rotationVector: FloatArray) {
SensorManager.getRotationMatrixFromVector(mRotationMatrix, rotationVector)
val (matrixColumn, sense) = when (mWindowManager.defaultDisplay.rotation) {
Surface.ROTATION_0 -> Pair(0, 1)
Surface.ROTATION_90 -> Pair(1, -1)
Surface.ROTATION_180 -> Pair(0, -1)
Surface.ROTATION_270 -> Pair(1, 1)
else -> error("Invalid screen rotation value")
}
val x = sense * mRotationMatrix[matrixColumn]
val y = sense * mRotationMatrix[matrixColumn + 3]
val azimuth = -atan2(y, x) * mOneRadDegrees
// SensorManager.getOrientation(mRotationMatrix, mOrientationValues)
// val azimuth = mOrientationValues[0] * mOneRadDegrees
val pitch = mOrientationValues[1] * mOneRadDegrees
val roll = mOrientationValues[2] * mOneRadDegrees
val magneticAzimuth = (azimuth + 360f) % 360f
val roundedAzimuth = round(magneticAzimuth * 10) / 10
mListener?.onOrientationChanged(roundedAzimuth, pitch, roll)
}
}
@@ -17,13 +17,7 @@
*/
package com.rtbishop.look4sat.ui.polarScreen
import android.content.Context
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import android.os.Bundle
import android.view.Surface
import android.view.View
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
@@ -37,100 +31,48 @@ import com.rtbishop.look4sat.utility.RecyclerDivider
import com.rtbishop.look4sat.utility.formatForTimer
import dagger.hilt.android.AndroidEntryPoint
import java.util.*
import kotlin.math.atan2
import kotlin.math.round
import javax.inject.Inject
@AndroidEntryPoint
class PolarFragment : Fragment(R.layout.fragment_polar), SensorEventListener {
class PolarFragment : Fragment(R.layout.fragment_polar), Orientation.OrientationListener {
@Inject
lateinit var orientation: Orientation
private lateinit var transmitterAdapter: TransAdapter
private lateinit var binding: FragmentPolarBinding
private lateinit var satPass: SatPass
private lateinit var sensorManager: SensorManager
private val viewModel: PolarViewModel by viewModels()
private val rotationMatrix = FloatArray(9)
private val orientationValues = FloatArray(3)
private var magneticDeclination = 0f
private var polarView: PolarView? = null
private var magneticDeclination = 0f
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentPolarBinding.bind(view)
sensorManager = requireContext().getSystemService(Context.SENSOR_SERVICE) as SensorManager
val binding = FragmentPolarBinding.bind(view)
val catNum = requireArguments().getInt("catNum")
val aosTime = requireArguments().getLong("aosTime")
magneticDeclination = viewModel.getMagDeclination()
observePass()
viewModel.getPass(catNum, aosTime).observe(viewLifecycleOwner) { pass ->
polarView = PolarView(requireContext()).apply { setPass(pass) }
binding.frame.addView(polarView)
observeTransmitters(pass, binding)
}
}
override fun onResume() {
super.onResume()
if (viewModel.shouldUseCompass()) {
sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR).also { sensor ->
sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_GAME)
}
}
if (viewModel.shouldUseCompass()) orientation.startListening(this)
}
override fun onPause() {
super.onPause()
if (viewModel.shouldUseCompass()) {
sensorManager.unregisterListener(this)
}
if (viewModel.shouldUseCompass()) orientation.stopListening()
}
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}
override fun onSensorChanged(event: SensorEvent?) {
event?.let { calculateAzimuth(it) }
override fun onOrientationChanged(azimuth: Float, pitch: Float, roll: Float) {
polarView?.rotation = -(azimuth + magneticDeclination)
}
private fun calculateAzimuth(event: SensorEvent) {
// if (event.sensor.type == Sensor.TYPE_ROTATION_VECTOR) {
// SensorManager.getRotationMatrixFromVector(rotationMatrix, event.values)
// SensorManager.getOrientation(rotationMatrix, orientationValues)
// val magneticAzimuth = (Math.toDegrees(orientationValues[0].toDouble()) + 360f) % 360f
// val roundedAzimuth = (round(magneticAzimuth * 10) / 10).toFloat()
// polarView?.rotation = -(roundedAzimuth + magneticDeclination)
// }
if (event.sensor.type == Sensor.TYPE_ROTATION_VECTOR) {
SensorManager.getRotationMatrixFromVector(rotationMatrix, event.values)
val (matrixColumn, sense) = when (val rotation =
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
requireContext().display?.rotation
} else {
@Suppress("DEPRECATION")
requireActivity().windowManager.defaultDisplay.rotation
}
) {
Surface.ROTATION_0 -> Pair(0, 1)
Surface.ROTATION_90 -> Pair(1, -1)
Surface.ROTATION_180 -> Pair(0, -1)
Surface.ROTATION_270 -> Pair(1, 1)
else -> error("Invalid screen rotation value: $rotation")
}
val x = sense * rotationMatrix[matrixColumn]
val y = sense * rotationMatrix[matrixColumn + 3]
val magneticAzimuth = (Math.toDegrees(-atan2(y, x).toDouble()) + 360f) % 360f
val roundedAzimuth = (round(magneticAzimuth * 10) / 10).toFloat()
polarView?.rotation = -(roundedAzimuth + magneticDeclination)
}
}
private fun observePass() {
val catNum = requireArguments().getInt("catNum")
val aosTime = requireArguments().getLong("aosTime")
viewModel.getPass(catNum, aosTime).observe(viewLifecycleOwner) { pass ->
satPass = pass
polarView = PolarView(requireContext()).apply { setPass(pass) }
binding.frame.addView(polarView)
observeTransmitters()
}
}
private fun observeTransmitters() {
viewModel.getSatTransmitters(satPass.catNum)
.observe(viewLifecycleOwner, { list ->
transmitterAdapter = TransAdapter(satPass)
private fun observeTransmitters(satPass: SatPass, binding: FragmentPolarBinding) {
viewModel.getSatTransmitters(satPass.catNum).observe(viewLifecycleOwner, { list ->
val transmitterAdapter = TransAdapter(satPass)
if (list.isNotEmpty()) {
transmitterAdapter.setData(list)
binding.recycler.apply {
@@ -147,19 +89,15 @@ class PolarFragment : Fragment(R.layout.fragment_polar), SensorEventListener {
binding.recycler.visibility = View.INVISIBLE
binding.noTransMsg.visibility = View.VISIBLE
}
observeTimer()
})
}
private fun observeTimer() {
viewModel.getAppTimer().observe(viewLifecycleOwner, {
setPassText(it)
setPassText(it, satPass, binding)
polarView?.invalidate()
transmitterAdapter.tickTransmitters()
})
})
}
private fun setPassText(timeNow: Long) {
private fun setPassText(timeNow: Long, satPass: SatPass, binding: FragmentPolarBinding) {
val dateNow = Date(timeNow)
val satPos = satPass.predictor.getSatPos(dateNow)
val polarAz = getString(R.string.pat_azimuth)