mirror of
https://github.com/atsunatsu/Look4Sat.git
synced 2026-10-02 03:15:37 +00:00
Extracted sensor listening logic from PolarFragment.kt to Orientation.kt
This commit is contained in:
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)
|
||||||
|
|||||||
Reference in new issue
Block a user