diff --git a/app/build.gradle b/app/build.gradle
index 8e092bca..49bb16de 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -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"
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 71c49a71..36643fee 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -5,11 +5,10 @@
-
-
+
- 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"
}
}
}
-
diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/radarScreen/RadarViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/radarScreen/RadarViewModel.kt
index 501d0d4e..df3ef8cf 100644
--- a/app/src/main/java/com/rtbishop/look4sat/presentation/radarScreen/RadarViewModel.kt
+++ b/app/src/main/java/com/rtbishop/look4sat/presentation/radarScreen/RadarViewModel.kt
@@ -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> = _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 = 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)
}
diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/settingsScreen/SettingsFragment.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/settingsScreen/SettingsFragment.kt
index 350e7ada..858c8890 100644
--- a/app/src/main/java/com/rtbishop/look4sat/presentation/settingsScreen/SettingsFragment.kt
+++ b/app/src/main/java/com/rtbishop/look4sat/presentation/settingsScreen/SettingsFragment.kt
@@ -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 {
diff --git a/app/src/main/res/layout/card_btremote.xml b/app/src/main/res/layout/card_btremote.xml
index ca72fc19..02d646bb 100644
--- a/app/src/main/res/layout/card_btremote.xml
+++ b/app/src/main/res/layout/card_btremote.xml
@@ -1,7 +1,6 @@
+ app:layout_constraintEnd_toEndOf="@+id/BTremote_switch"
+ app:layout_constraintStart_toStartOf="@+id/BTremote_switch"
+ app:layout_constraintTop_toBottomOf="@id/BTremote_switch">
-
+
+ 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">
@@ -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" />
diff --git a/app/src/main/res/layout/dialog_position.xml b/app/src/main/res/layout/dialog_position.xml
index e64bbbdb..50cbe535 100644
--- a/app/src/main/res/layout/dialog_position.xml
+++ b/app/src/main/res/layout/dialog_position.xml
@@ -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" />
@@ -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" />
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 0ba55032..4643906b 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -138,6 +138,12 @@
IP адрес
Порт
+ Передача данных по Bluetooth
+ Включить передачу
+ Id устройства
+ Формат данных
+ Нет разрешения использовать bluetooth
+
Другие настройки
Показывать время по UTC
Показывать анимацию радара
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index d20ef091..14851d68 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -139,10 +139,11 @@
IP address
Port
- Bluetooth Output
- Enable Bluetooth
- Device
- Output format
+ Bluetooth data output
+ Enable output
+ Device id
+ Data format
+ Check your bluetooth permission
Other preferences
Show pass time in UTC
diff --git a/base/build.gradle b/base/build.gradle
index db00cc2c..dc1c7649 100644
--- a/base/build.gradle
+++ b/base/build.gradle
@@ -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"
}
diff --git a/base/src/main/java/com/rtbishop/look4sat/utility/Extensions.kt b/base/src/main/java/com/rtbishop/look4sat/utility/Extensions.kt
index 75f3928c..ff107572 100644
--- a/base/src/main/java/com/rtbishop/look4sat/utility/Extensions.kt
+++ b/base/src/main/java/com/rtbishop/look4sat/utility/Extensions.kt
@@ -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 {
diff --git a/build.gradle b/build.gradle
index 5e9a22d8..ac4163ee 100644
--- a/build.gradle
+++ b/build.gradle
@@ -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"
}
}