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.ContentResolver
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.hardware.SensorManager
import android.location.LocationManager import android.location.LocationManager
import android.view.WindowManager
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
@@ -42,6 +44,16 @@ object ApplicationModule {
return context.getSystemService(Context.LOCATION_SERVICE) as LocationManager 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 @Provides
fun provideSharedPreferences(@ApplicationContext context: Context): SharedPreferences { fun provideSharedPreferences(@ApplicationContext context: Context): SharedPreferences {
return PreferenceManager.getDefaultSharedPreferences(context) 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 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.os.Bundle
import android.view.Surface
import android.view.View import android.view.View
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
@@ -37,100 +31,48 @@ import com.rtbishop.look4sat.utility.RecyclerDivider
import com.rtbishop.look4sat.utility.formatForTimer import com.rtbishop.look4sat.utility.formatForTimer
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import java.util.* import java.util.*
import kotlin.math.atan2 import javax.inject.Inject
import kotlin.math.round
@AndroidEntryPoint @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 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 polarView: PolarView? = null
private var magneticDeclination = 0f
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
binding = FragmentPolarBinding.bind(view) val binding = FragmentPolarBinding.bind(view)
sensorManager = requireContext().getSystemService(Context.SENSOR_SERVICE) as SensorManager val catNum = requireArguments().getInt("catNum")
val aosTime = requireArguments().getLong("aosTime")
magneticDeclination = viewModel.getMagDeclination() 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() { override fun onResume() {
super.onResume() super.onResume()
if (viewModel.shouldUseCompass()) { if (viewModel.shouldUseCompass()) orientation.startListening(this)
sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR).also { sensor ->
sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_GAME)
}
}
} }
override fun onPause() { override fun onPause() {
super.onPause() super.onPause()
if (viewModel.shouldUseCompass()) { if (viewModel.shouldUseCompass()) orientation.stopListening()
sensorManager.unregisterListener(this)
}
} }
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {} override fun onOrientationChanged(azimuth: Float, pitch: Float, roll: Float) {
polarView?.rotation = -(azimuth + magneticDeclination)
override fun onSensorChanged(event: SensorEvent?) {
event?.let { calculateAzimuth(it) }
} }
private fun calculateAzimuth(event: SensorEvent) { private fun observeTransmitters(satPass: SatPass, binding: FragmentPolarBinding) {
// if (event.sensor.type == Sensor.TYPE_ROTATION_VECTOR) { viewModel.getSatTransmitters(satPass.catNum).observe(viewLifecycleOwner, { list ->
// SensorManager.getRotationMatrixFromVector(rotationMatrix, event.values) val transmitterAdapter = TransAdapter(satPass)
// 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)
if (list.isNotEmpty()) { if (list.isNotEmpty()) {
transmitterAdapter.setData(list) transmitterAdapter.setData(list)
binding.recycler.apply { binding.recycler.apply {
@@ -147,19 +89,15 @@ class PolarFragment : Fragment(R.layout.fragment_polar), SensorEventListener {
binding.recycler.visibility = View.INVISIBLE binding.recycler.visibility = View.INVISIBLE
binding.noTransMsg.visibility = View.VISIBLE binding.noTransMsg.visibility = View.VISIBLE
} }
observeTimer()
})
}
private fun observeTimer() {
viewModel.getAppTimer().observe(viewLifecycleOwner, { viewModel.getAppTimer().observe(viewLifecycleOwner, {
setPassText(it) setPassText(it, satPass, binding)
polarView?.invalidate() polarView?.invalidate()
transmitterAdapter.tickTransmitters() transmitterAdapter.tickTransmitters()
}) })
})
} }
private fun setPassText(timeNow: Long) { private fun setPassText(timeNow: Long, satPass: SatPass, binding: FragmentPolarBinding) {
val dateNow = Date(timeNow) val dateNow = Date(timeNow)
val satPos = satPass.predictor.getSatPos(dateNow) val satPos = satPass.predictor.getSatPos(dateNow)
val polarAz = getString(R.string.pat_azimuth) val polarAz = getString(R.string.pat_azimuth)