Minor fixes to strings and ui, crash fixed #63

This commit is contained in:
Arty Bishop committed 2022-05-18 19:00:48 +01:00
1 parent a2f37e6b9f
commit 278c06170b
16 files changed
+157 -177

No files matched your search

+2 -2
View File
@@ -43,7 +43,7 @@ android {
}
testOptions {
animationsDisabled true
unitTests.includeAndroidResources = true
unitTests.includeAndroidResources true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
@@ -56,7 +56,7 @@ android {
dependencies {
implementation project(":base")
implementation "androidx.core:core-splashscreen:1.0.0-beta01"
implementation "androidx.core:core-splashscreen:1.0.0-beta02"
implementation "androidx.constraintlayout:constraintlayout:2.1.3"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.1"
+1 -2
View File
@@ -5,11 +5,10 @@
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:name=".presentation.MainApplication"
@@ -39,8 +39,8 @@ class SettingsManager @Inject constructor(private val prefs: SharedPreferences)
const val keyRotatorAddress = "rotatorAddress"
const val keyRotatorPort = "rotatorPort"
const val keyBTEnabled = "isBTEnabled"
const val keyBTDeviceName = "BTDevice"
const val keyBTDeviceAddr = "BTDevice"
const val keyBTDeviceName = "BTDeviceName"
const val keyBTDeviceAddr = "BTDeviceAddr"
const val keyBTFormat = "BTFormat"
const val keyLatitude = "stationLat"
const val keyLongitude = "stationLon"
@@ -153,7 +153,7 @@ class SettingsManager @Inject constructor(private val prefs: SharedPreferences)
}
override fun getBTEnabled(): Boolean {
return prefs.getBoolean(keyBTEnabled, true)
return prefs.getBoolean(keyBTEnabled, false)
}
override fun setBTEnabled(value: Boolean) {
@@ -17,6 +17,7 @@
*/
package com.rtbishop.look4sat.injection
import android.bluetooth.BluetoothManager
import android.content.Context
import android.content.SharedPreferences
import android.hardware.SensorManager
@@ -32,6 +33,12 @@ import javax.inject.Singleton
@InstallIn(SingletonComponent::class)
object AppModule {
@Provides
@Singleton
fun provideBluetoothManager(@ApplicationContext context: Context): BluetoothManager {
return context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
}
@Provides
@Singleton
fun provideLocationManager(@ApplicationContext context: Context): LocationManager {
@@ -17,6 +17,7 @@
*/
package com.rtbishop.look4sat.injection
import android.bluetooth.BluetoothManager
import android.content.Context
import androidx.room.Room
import com.rtbishop.look4sat.domain.IDataRepository
@@ -65,7 +66,9 @@ object BaseModule {
@Provides
@Singleton
fun provideBTReporter(): BTReporter = BTReporter(CoroutineScope(Dispatchers.IO))
fun provideBTReporter(manager: BluetoothManager): BTReporter {
return BTReporter(manager, CoroutineScope(Dispatchers.IO))
}
@Provides
@Singleton
@@ -1,134 +1,83 @@
package com.rtbishop.look4sat.presentation.radarScreen
import android.Manifest
import android.content.Context
import android.bluetooth.BluetoothManager
import android.util.Log
import android.widget.Toast
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.launch
import java.net.InetSocketAddress
import java.nio.ByteBuffer
import java.nio.channels.SocketChannel
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothManager
import android.bluetooth.BluetoothSocket
import android.content.pm.PackageManager
import androidx.core.app.ActivityCompat
import java.io.OutputStream
import java.util.*
import kotlin.math.abs
class BTReporter(private val reporterScope: CoroutineScope) {
class BTReporter(private val manager: BluetoothManager, private val reporterScope: CoroutineScope) {
private var rotationConnectBTJob: Job? = null
private var rotationReportingBT: Job? = null
private var satVisible=false
private var CRchar:Char = '\r'
private var NLchar:Char = '\n'
private var TBchar:Char = '\t'
private val bluetoothAdapter: BluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
private lateinit var mmOutStream: OutputStream
private val SPPID: UUID=UUID.fromString("00001101-0000-1000-8000-00805f9b34fb")
private val tag = "BTReporter"
private val sppid: UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb")
private lateinit var outputStream: OutputStream
private var rotationConnectionJob: Job? = null
private var rotationReportingJob: Job? = null
private var connected = false
private var connectInProgress = false
private var connecting = false
fun connectBTDevice(dev: String) {
fun isConnected(): Boolean = connected
fun isConnecting(): Boolean = connecting
@Suppress("BlockingMethodInNonBlockingContext")
fun connectBTDevice(deviceId: String) {
if (!connected) {
rotationConnectBTJob = reporterScope.launch {
runCatching {
connectInProgress = true
val rotationBTDevice = bluetoothAdapter.getRemoteDevice(dev)
val sock = rotationBTDevice.createInsecureRfcommSocketToServiceRecord(SPPID)
sock.connect()
mmOutStream = sock.outputStream
connected = true
connectInProgress = false
Log.i("look4satBT", "Connected!")
}.onFailure { error: Throwable ->
Log.e("BT Error", "${error.message}")
rotationConnectionJob = reporterScope.launch {
try {
manager.adapter.getRemoteDevice(deviceId)?.let { device ->
device.createInsecureRfcommSocketToServiceRecord(sppid)?.let { socket ->
connecting = true
socket.connect()
outputStream = socket.outputStream
connected = true
connecting = false
Log.i(tag, "$tag: Connected!")
}
}
} catch (e: SecurityException) {
Log.e(tag, "$tag: ${e.message}")
} catch (e: Exception) {
Log.e(tag, "$tag: ${e.message}")
}
}
}
}
fun isBTConnected():Boolean
{
return connected
@Suppress("BlockingMethodInNonBlockingContext")
fun reportRotation(format: String, azimuth: Int, elevation: Int) {
if (connected) {
rotationReportingJob = reporterScope.launch {
try {
val azimuthString = intToStringWithLeadingZeroes(azimuth)
val elevationString = intToStringWithLeadingZeroes(elevation)
val crChar = '\r'
val nlChar = '\n'
val tbChar = '\t'
var buffer = format.replace("\$AZ", azimuthString)
buffer = buffer.replace("\$EL", elevationString)
buffer = buffer.replace("\\r", crChar.toString())
buffer = buffer.replace("\\n", nlChar.toString())
buffer = buffer.replace("\\t", tbChar.toString())
Log.i(tag, "$tag: Sending $buffer")
if (connected) outputStream.write(buffer.toByteArray())
} catch (e: Exception) {
Log.e(tag, "$tag: ${e.message}")
connected = false
}
}
}
}
fun connectInProg():Boolean
{
return connectInProgress
}
fun reportRotationBT(dev: String, fmt: String, AZ: Int, EL: Int) {
runCatching {
var azStr:String
var elStr:String
satVisible=(EL>1)
//Need to add leading zeros to string to ensure always 3 digits.
//Ideally this could be done via the format string but this will do for now.
if(AZ<100){
if(AZ<10){
azStr="00"
}
else
{
azStr="0"
}
azStr=azStr.plus(AZ.toString())
}
else
{
azStr=AZ.toString()
}
if(EL<100){
if(EL<10){
elStr="00"
}
else
{
elStr="0"
}
if(satVisible) {
elStr = elStr.plus(EL.toString())
}
else {
elStr="000"
}
}
else
{
elStr=EL.toString()
}
var buffer = fmt.replace("\$AZ",azStr)
buffer = buffer.replace("\$EL",elStr)
buffer = buffer.replace("\\r",CRchar.toString())
buffer = buffer.replace("\\n",NLchar.toString())
buffer = buffer.replace("\\t",TBchar.toString())
Log.i("Output is", buffer)
if(connected) {
Log.i("Sending BT", buffer)
this.mmOutStream.write(buffer.toByteArray())
Log.i("Sent", buffer)
}
}.onFailure { error: Throwable ->
Log.e("BT Error","${error.message}")
connected=false
private fun intToStringWithLeadingZeroes(value: Int): String {
return if (value > 0) {
if (value < 10) "00$value" else if (value < 100) "0$value" else "$value"
} else {
val absValue = abs(value)
if (value > -10) "-00$absValue" else if (value > -100) "-0$absValue" else "-$absValue"
}
}
}
@@ -42,8 +42,8 @@ import javax.inject.Inject
class RadarViewModel @Inject constructor(
private val orientationManager: OrientationManager,
private val reporter: DataReporter,
private val BTreporter: BTReporter,
private val satelliteManager: ISatelliteManager,
private val btReporter: BTReporter,
private val satManager: ISatelliteManager,
private val repository: IDataRepository,
private val settings: ISettingsManager
) : ViewModel(), OrientationManager.OrientationListener {
@@ -57,7 +57,7 @@ class RadarViewModel @Inject constructor(
val orientation: LiveData<Triple<Float, Float, Float>> = _orientation
fun getPass(catNum: Int, aosTime: Long) = liveData {
satelliteManager.calculatedPasses.collect { passes ->
satManager.calculatedPasses.collect { passes ->
val pass = passes.find { pass -> pass.catNum == catNum && pass.aosTime == aosTime }
pass?.let { satPass ->
emit(satPass)
@@ -94,12 +94,11 @@ class RadarViewModel @Inject constructor(
viewModelScope.launch {
var satTrack: List<SatPos> = emptyList()
if (!satPass.isDeepSpace) {
val startDate = satPass.aosTime
val endDate = satPass.losTime
satTrack = satelliteManager.getTrack(satPass.satellite, stationPos, startDate, endDate)
satTrack = satManager
.getTrack(satPass.satellite, stationPos, satPass.aosTime, satPass.losTime)
}
while (isActive) {
val satPos = satelliteManager.getPosition(satPass.satellite, stationPos, Date().time)
val satPos = satManager.getPosition(satPass.satellite, stationPos, Date().time)
if (settings.getRotatorEnabled()) {
val server = settings.getRotatorServer()
val port = settings.getRotatorPort().toInt()
@@ -116,21 +115,20 @@ class RadarViewModel @Inject constructor(
private fun sendPassDataBT(satPass: SatPass) {
viewModelScope.launch {
while (isActive) {
val satPos = satelliteManager.getPosition(satPass.satellite, stationPos, Date().time)
val satPos = satManager.getPosition(satPass.satellite, stationPos, Date().time)
if (settings.getBTEnabled()) {
val server = settings.getBTDeviceAddr()
if(BTreporter.isBTConnected()) {
val port = settings.getBTFormat()
val btDevice = settings.getBTDeviceAddr()
if (btReporter.isConnected()) {
val format = settings.getBTFormat()
val azimuth = satPos.azimuth.toDegrees().round(0).toInt()
val elevation = satPos.elevation.toDegrees().round(0).toInt()
BTreporter.reportRotationBT(server, port, azimuth, elevation)
}
else if(!BTreporter.connectInProg()) {
Log.i("look4satBT", "Attempting to connect...")
BTreporter.connectBTDevice(server)
btReporter.reportRotation(format, azimuth, elevation)
} else if (!btReporter.isConnecting()) {
Log.i("BTReporter", "BTReporter: Attempting to connect...")
btReporter.connectBTDevice(btDevice)
}
}
delay(2000)
delay(1000)
}
}
}
@@ -141,7 +139,7 @@ class RadarViewModel @Inject constructor(
val transmitters = repository.getRadiosWithId(pass.catNum)
while (isActive) {
val time = System.currentTimeMillis()
val list = satelliteManager.processRadios(pass.satellite, stationPos, transmitters, time)
val list = satManager.processRadios(pass.satellite, stationPos, transmitters, time)
_transmitters.postValue(list)
delay(1000)
}
@@ -17,15 +17,13 @@
*/
package com.rtbishop.look4sat.presentation.settingsScreen
//import com.rtbishop.look4sat.BuildConfig
import android.Manifest
import android.bluetooth.BluetoothAdapter
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.text.method.LinkMovementMethod
import android.view.View
import android.widget.ArrayAdapter
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.widget.NestedScrollView
@@ -34,6 +32,7 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.asLiveData
import androidx.navigation.fragment.findNavController
import com.rtbishop.look4sat.BuildConfig
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.FragmentSettingsBinding
import com.rtbishop.look4sat.domain.model.DataState
@@ -44,11 +43,21 @@ import com.rtbishop.look4sat.utility.isValidIPv4
import com.rtbishop.look4sat.utility.isValidPort
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class SettingsFragment : Fragment(R.layout.fragment_settings) {
private val viewModel: SettingsViewModel by viewModels()
private val bluetooth = when {
Build.VERSION.SDK_INT < Build.VERSION_CODES.S -> Manifest.permission.BLUETOOTH
else -> Manifest.permission.BLUETOOTH_CONNECT
}
private val bluetoothContract = ActivityResultContracts.RequestPermission()
private val bluetoothRequest = registerForActivityResult(bluetoothContract) { isGranted ->
if (!isGranted) {
showToast(getString(R.string.BTremote_perm_error))
toggleBTstate(isGranted)
}
}
private val locationFine = Manifest.permission.ACCESS_FINE_LOCATION
private val locationCoarse = Manifest.permission.ACCESS_COARSE_LOCATION
private val locationContract = ActivityResultContracts.RequestMultiplePermissions()
@@ -73,7 +82,7 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
if (y > newY) settingsFab.hide() else settingsFab.show()
})
settingsAbout.aboutVersion.text =
String.format(getString(R.string.app_version), 0)
String.format(getString(R.string.app_version), BuildConfig.VERSION_NAME)
settingsBtnGithub.clickWithDebounce {
gotoUrl("https://github.com/rt-bishop/Look4Sat/")
}
@@ -84,8 +93,6 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
gotoUrl("https://f-droid.org/en/packages/com.rtbishop.look4sat/")
}
}
setupLocationCard()
setupDataCard()
setupRemoteCard()
@@ -154,7 +161,6 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
settingsRemote.remotePort.isEnabled = isChecked
settingsRemote.remotePortEdit.setText(viewModel.getRotatorPort())
setOnCheckedChangeListener { _, isChecked ->
viewModel.setRotatorEnabled(isChecked)
settingsRemote.remoteIp.isEnabled = isChecked
settingsRemote.remotePort.isEnabled = isChecked
}
@@ -169,31 +175,36 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
}
private fun setupBTCard() {
binding.run {
settingsBtremote.BTremoteSwitch.apply {
isChecked = viewModel.getBTEnabled()
settingsBtremote.BTremoteAddress.isEnabled = isChecked
settingsBtremote.BTremoteFormat.isEnabled = isChecked
settingsBtremote.BTAddressEdit.setText(viewModel.getBTDeviceAddr())
settingsBtremote.BTremoteFormat.isEnabled = isChecked
settingsBtremote.BTFormatEdit.setText(viewModel.getBTFormat())
setOnCheckedChangeListener { _, isChecked ->
viewModel.setBTEnabled(isChecked)
settingsBtremote.BTremoteAddress.isEnabled = isChecked
settingsBtremote.BTremoteFormat.isEnabled = isChecked
toggleBTstate(isChecked)
bluetoothRequest.launch(bluetooth)
}
}
settingsBtremote.BTAddressEdit.doOnTextChanged { text, _, _, _ ->
viewModel.setBTDeviceAddr(text.toString())
}
settingsBtremote.BTFormatEdit.doOnTextChanged { text, _, _, _ ->
viewModel.setBTFormat(text.toString())
}
}
}
private fun toggleBTstate(value: Boolean) {
binding.run {
viewModel.setBTEnabled(value)
settingsBtremote.BTremoteSwitch.isChecked = value
settingsBtremote.BTremoteAddress.isEnabled = value
settingsBtremote.BTremoteFormat.isEnabled = value
}
}
private fun setupOtherCard() {
binding.run {
settingsOther.otherSwitchUtc.apply {
+15 -15
View File
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
style="@style/SurfaceCard">
<androidx.constraintlayout.widget.ConstraintLayout
@@ -38,27 +37,28 @@
android:id="@+id/BTremote_address"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/BTremote_switch"
app:layout_constraintEnd_toEndOf="@+id/BTremote_title"
app:layout_constraintStart_toStartOf="@+id/BTremote_title"
tools:layout_editor_absoluteY="70dp">
app:layout_constraintEnd_toEndOf="@+id/BTremote_switch"
app:layout_constraintStart_toStartOf="@+id/BTremote_switch"
app:layout_constraintTop_toBottomOf="@id/BTremote_switch">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/BT_address_edit"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hint="@string/BTremote_device_hint"
android:textColorHint="@color/textMain" />
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/BT_address_edit"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hint="@string/BTremote_device_hint"
android:textColorHint="@color/textMain" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/BTremote_format"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/BTremote_address"
app:layout_constraintEnd_toEndOf="@+id/BTremote_title"
app:layout_constraintStart_toStartOf="@+id/BTremote_title"
tools:layout_editor_absoluteY="70dp">
android:layout_marginTop="6dp"
android:layout_marginBottom="12dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/BTremote_address"
app:layout_constraintStart_toStartOf="@+id/BTremote_address"
app:layout_constraintTop_toBottomOf="@id/BTremote_address">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/BT_format_edit"
+3
View File
@@ -48,7 +48,9 @@
android:id="@+id/remote_ip_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:digits="0123456789."
android:hint="@string/remote_ip_hint"
android:inputType="number"
android:textColorHint="@color/textMain" />
</com.google.android.material.textfield.TextInputLayout>
@@ -67,6 +69,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/remote_port_hint"
android:inputType="number"
android:textColorHint="@color/textMain" />
</com.google.android.material.textfield.TextInputLayout>
+4 -2
View File
@@ -57,7 +57,8 @@
android:id="@+id/position_lat_edit"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inputType="textUri" />
android:digits="0123456789."
android:inputType="number" />
</com.google.android.material.textfield.TextInputLayout>
@@ -94,7 +95,8 @@
android:id="@+id/position_lon_edit"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inputType="textUri" />
android:digits="0123456789."
android:inputType="number" />
</com.google.android.material.textfield.TextInputLayout>
+6
View File
@@ -138,6 +138,12 @@
<string name="remote_ip_hint">IP адрес</string>
<string name="remote_port_hint">Порт</string>
<string name="BTremote_title">Передача данных по Bluetooth</string>
<string name="BTremote_switch">Включить передачу</string>
<string name="BTremote_device_hint">Id устройства</string>
<string name="BTremote_output_hint">Формат данных</string>
<string name="BTremote_perm_error">Нет разрешения использовать bluetooth</string>
<string name="other_title">Другие настройки</string>
<string name="other_switch_utc">Показывать время по UTC</string>
<string name="other_switch_sweep">Показывать анимацию радара</string>
+5 -4
View File
@@ -139,10 +139,11 @@
<string name="remote_ip_hint">IP address</string>
<string name="remote_port_hint">Port</string>
<string name="BTremote_title">Bluetooth Output</string>
<string name="BTremote_switch">Enable Bluetooth</string>
<string name="BTremote_device_hint">Device</string>
<string name="BTremote_output_hint">Output format</string>
<string name="BTremote_title">Bluetooth data output</string>
<string name="BTremote_switch">Enable output</string>
<string name="BTremote_device_hint">Device id</string>
<string name="BTremote_output_hint">Data format</string>
<string name="BTremote_perm_error">Check your bluetooth permission</string>
<string name="other_title">Other preferences</string>
<string name="other_switch_utc">Show pass time in UTC</string>
+2 -2
View File
@@ -13,9 +13,9 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0"
implementation "org.json:json:20211205"
implementation "org.json:json:20220320"
testImplementation "junit:junit:4.13.2"
testImplementation "org.mockito:mockito-core:4.3.1"
testImplementation "org.mockito:mockito-core:4.4.0"
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.0"
}
@@ -67,7 +67,8 @@ fun String.isValidIPv4(): Boolean {
}
fun String.isValidPort(): Boolean {
return this.isNotEmpty() && this.toInt() in 1024..65535
val port = "([1-9]|[1-9]\\d{1,3}|[1-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5])"
return this.matches(port.toRegex()) && this.toInt() in 1024..65535
}
fun ping(hostname: String, port: Int): Int {
+1 -1
View File
@@ -1,6 +1,6 @@
buildscript {
dependencies {
classpath "com.google.dagger:hilt-android-gradle-plugin:2.40.5"
classpath "com.google.dagger:hilt-android-gradle-plugin:2.41"
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.4.1"
}
}