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
+149 -105

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
@@ -31,17 +33,27 @@ import dagger.hilt.components.SingletonComponent
@Module @Module
@InstallIn(SingletonComponent::class) @InstallIn(SingletonComponent::class)
object ApplicationModule { object ApplicationModule {
@Provides @Provides
fun provideContentResolver(@ApplicationContext context: Context): ContentResolver { fun provideContentResolver(@ApplicationContext context: Context): ContentResolver {
return context.contentResolver return context.contentResolver
} }
@Provides @Provides
fun provideLocationManager(@ApplicationContext context: Context): LocationManager { fun provideLocationManager(@ApplicationContext context: Context): LocationManager {
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,129 +31,73 @@ 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) if (list.isNotEmpty()) {
// val magneticAzimuth = (Math.toDegrees(orientationValues[0].toDouble()) + 360f) % 360f transmitterAdapter.setData(list)
// val roundedAzimuth = (round(magneticAzimuth * 10) / 10).toFloat() binding.recycler.apply {
// polarView?.rotation = -(roundedAzimuth + magneticDeclination) setHasFixedSize(true)
// } adapter = transmitterAdapter
isVerticalScrollBarEnabled = false
if (event.sensor.type == Sensor.TYPE_ROTATION_VECTOR) { layoutManager = LinearLayoutManager(context)
SensorManager.getRotationMatrixFromVector(rotationMatrix, event.values) (itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
val (matrixColumn, sense) = when (val rotation = addItemDecoration(RecyclerDivider(R.drawable.rec_divider_dark))
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) { visibility = View.VISIBLE
requireContext().display?.rotation
} else {
@Suppress("DEPRECATION")
requireActivity().windowManager.defaultDisplay.rotation
} }
) { binding.noTransMsg.visibility = View.INVISIBLE
Surface.ROTATION_0 -> Pair(0, 1) } else {
Surface.ROTATION_90 -> Pair(1, -1) binding.recycler.visibility = View.INVISIBLE
Surface.ROTATION_180 -> Pair(0, -1) binding.noTransMsg.visibility = View.VISIBLE
Surface.ROTATION_270 -> Pair(1, 1)
else -> error("Invalid screen rotation value: $rotation")
} }
val x = sense * rotationMatrix[matrixColumn] viewModel.getAppTimer().observe(viewLifecycleOwner, {
val y = sense * rotationMatrix[matrixColumn + 3] setPassText(it, satPass, binding)
val magneticAzimuth = (Math.toDegrees(-atan2(y, x).toDouble()) + 360f) % 360f polarView?.invalidate()
val roundedAzimuth = (round(magneticAzimuth * 10) / 10).toFloat() transmitterAdapter.tickTransmitters()
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()) {
transmitterAdapter.setData(list)
binding.recycler.apply {
setHasFixedSize(true)
adapter = transmitterAdapter
isVerticalScrollBarEnabled = false
layoutManager = LinearLayoutManager(context)
(itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
addItemDecoration(RecyclerDivider(R.drawable.rec_divider_dark))
visibility = View.VISIBLE
}
binding.noTransMsg.visibility = View.INVISIBLE
} else {
binding.recycler.visibility = View.INVISIBLE
binding.noTransMsg.visibility = View.VISIBLE
}
observeTimer()
}) })
}
private fun observeTimer() {
viewModel.getAppTimer().observe(viewLifecycleOwner, {
setPassText(it)
polarView?.invalidate()
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)