Skip to content

Commit

Permalink
Adds scan rate information to the bluetooth and wifi details screens
Browse files Browse the repository at this point in the history
  • Loading branch information
christianrowlands committed Jan 10, 2024
1 parent 815314d commit 80790c0
Show file tree
Hide file tree
Showing 12 changed files with 342 additions and 149 deletions.
2 changes: 1 addition & 1 deletion networksurvey/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ dependencies {
implementation "androidx.navigation:navigation-runtime-ktx:${navigationVersion}"
implementation "androidx.navigation:navigation-fragment-ktx:${navigationVersion}"
implementation "androidx.navigation:navigation-ui-ktx:${navigationVersion}"
implementation "androidx.navigation:navigation-compose:${navigationVersion}"
implementation "androidx.viewpager2:viewpager2:1.0.0"
implementation 'com.google.android.flexbox:flexbox:3.0.0'

Expand Down Expand Up @@ -126,7 +127,6 @@ dependencies {
implementation "androidx.compose.ui:ui"
implementation "androidx.compose.foundation:foundation"
implementation "androidx.compose.foundation:foundation-layout"
implementation "androidx.compose.material:material"
implementation "androidx.compose.material3:material3"
implementation "androidx.compose.runtime:runtime-livedata"
implementation "androidx.compose.ui:ui-tooling"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
package com.craxiom.networksurvey.fragments

import android.content.SharedPreferences
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import androidx.preference.PreferenceManager
import com.craxiom.messaging.BluetoothRecord
import com.craxiom.messaging.BluetoothRecordData
import com.craxiom.networksurvey.constants.NetworkSurveyConstants
import com.craxiom.networksurvey.constants.NetworkSurveyConstants.PROPERTY_BLUETOOTH_SCAN_INTERVAL_SECONDS
import com.craxiom.networksurvey.listeners.IBluetoothSurveyRecordListener
import com.craxiom.networksurvey.services.NetworkSurveyService
import com.craxiom.networksurvey.ui.UNKNOWN_RSSI
import com.craxiom.networksurvey.ui.bluetooth.BluetoothDetailsScreen
import com.craxiom.networksurvey.ui.bluetooth.BluetoothDetailsViewModel
import com.craxiom.networksurvey.util.NsTheme
import com.craxiom.networksurvey.util.PreferenceUtils
import timber.log.Timber

/**
Expand All @@ -25,6 +31,19 @@ class BluetoothDetailsFragment : AServiceDataFragment(), IBluetoothSurveyRecordL
private lateinit var bluetoothData: BluetoothRecordData
private lateinit var viewModel: BluetoothDetailsViewModel

private lateinit var sharedPreferences: SharedPreferences
private val preferenceChangeListener =
SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
if (key == PROPERTY_BLUETOOTH_SCAN_INTERVAL_SECONDS) {
val bluetoothScanRateMs = PreferenceUtils.getScanRatePreferenceMs(
PROPERTY_BLUETOOTH_SCAN_INTERVAL_SECONDS,
NetworkSurveyConstants.DEFAULT_BLUETOOTH_SCAN_INTERVAL_SECONDS,
context
)
viewModel.setScanRateSeconds(bluetoothScanRateMs / 1_000)
}
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
Expand All @@ -46,7 +65,10 @@ class BluetoothDetailsFragment : AServiceDataFragment(), IBluetoothSurveyRecordL
viewModel.addInitialRssi(UNKNOWN_RSSI)
}
NsTheme {
BluetoothDetailsScreen(viewModel = viewModel)
BluetoothDetailsScreen(
viewModel = viewModel,
bluetoothDetailsFragment = this@BluetoothDetailsFragment
)
}
}
}
Expand All @@ -57,9 +79,26 @@ class BluetoothDetailsFragment : AServiceDataFragment(), IBluetoothSurveyRecordL
override fun onResume() {
super.onResume()

context?.let { context ->
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
sharedPreferences.registerOnSharedPreferenceChangeListener(preferenceChangeListener)
val scanRateMs = PreferenceUtils.getScanRatePreferenceMs(
PROPERTY_BLUETOOTH_SCAN_INTERVAL_SECONDS,
NetworkSurveyConstants.DEFAULT_BLUETOOTH_SCAN_INTERVAL_SECONDS,
context
)
viewModel.setScanRateSeconds(scanRateMs / 1_000)
}

startAndBindToService()
}

override fun onPause() {
sharedPreferences.unregisterOnSharedPreferenceChangeListener(preferenceChangeListener)

super.onPause()
}

override fun onSurveyServiceConnected(service: NetworkSurveyService?) {
if (service == null) return
service.registerBluetoothSurveyRecordListener(this)
Expand Down Expand Up @@ -100,4 +139,11 @@ class BluetoothDetailsFragment : AServiceDataFragment(), IBluetoothSurveyRecordL

}
}

/**
* Navigates to the Settings UI (primarily for the user to change the scan rate)
*/
fun navigateToSettings() {
findNavController().navigate(BluetoothDetailsFragmentDirections.actionBluetoothDetailsToSettings())
}
}
Original file line number Diff line number Diff line change
@@ -1,27 +1,48 @@
package com.craxiom.networksurvey.fragments

import android.content.SharedPreferences
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import androidx.preference.PreferenceManager
import com.craxiom.networksurvey.constants.NetworkSurveyConstants
import com.craxiom.networksurvey.listeners.IWifiSurveyRecordListener
import com.craxiom.networksurvey.model.WifiNetwork
import com.craxiom.networksurvey.model.WifiRecordWrapper
import com.craxiom.networksurvey.services.NetworkSurveyService
import com.craxiom.networksurvey.ui.wifi.UNKNOWN_RSSI
import com.craxiom.networksurvey.ui.UNKNOWN_RSSI
import com.craxiom.networksurvey.ui.wifi.WifiDetailsScreen
import com.craxiom.networksurvey.ui.wifi.WifiDetailsViewModel
import com.craxiom.networksurvey.util.NsTheme
import com.craxiom.networksurvey.util.PreferenceUtils
import timber.log.Timber

/**
* The fragment that displays the details of a single Wifi network from the scan results.
*/
class WifiDetailsFragment : AServiceDataFragment(), IWifiSurveyRecordListener {
private lateinit var wifiNetwork: WifiNetwork
private lateinit var viewModel: WifiDetailsViewModel

private lateinit var sharedPreferences: SharedPreferences
private val preferenceChangeListener =
SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
if (key == NetworkSurveyConstants.PROPERTY_WIFI_SCAN_INTERVAL_SECONDS) {
val bluetoothScanRateMs = PreferenceUtils.getScanRatePreferenceMs(
NetworkSurveyConstants.PROPERTY_WIFI_SCAN_INTERVAL_SECONDS,
NetworkSurveyConstants.DEFAULT_WIFI_SCAN_INTERVAL_SECONDS,
context
)
viewModel.setScanRateSeconds(bluetoothScanRateMs / 1_000)
}
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
Expand All @@ -43,7 +64,10 @@ class WifiDetailsFragment : AServiceDataFragment(), IWifiSurveyRecordListener {
viewModel.addInitialRssi(wifiNetwork.signalStrength!!)
}
NsTheme {
WifiDetailsScreen(viewModel = viewModel)
WifiDetailsScreen(
viewModel = viewModel,
wifiDetailsFragment = this@WifiDetailsFragment
)
}
}
}
Expand All @@ -54,9 +78,26 @@ class WifiDetailsFragment : AServiceDataFragment(), IWifiSurveyRecordListener {
override fun onResume() {
super.onResume()

context?.let { context ->
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
sharedPreferences.registerOnSharedPreferenceChangeListener(preferenceChangeListener)
val scanRateMs = PreferenceUtils.getScanRatePreferenceMs(
NetworkSurveyConstants.PROPERTY_WIFI_SCAN_INTERVAL_SECONDS,
NetworkSurveyConstants.DEFAULT_WIFI_SCAN_INTERVAL_SECONDS,
context
)
viewModel.setScanRateSeconds(scanRateMs / 1_000)
}

startAndBindToService()
}

override fun onPause() {
sharedPreferences.unregisterOnSharedPreferenceChangeListener(preferenceChangeListener)

super.onPause()
}

override fun onSurveyServiceConnected(service: NetworkSurveyService?) {
if (service == null) return
service.registerWifiSurveyRecordListener(this)
Expand Down Expand Up @@ -85,4 +126,11 @@ class WifiDetailsFragment : AServiceDataFragment(), IWifiSurveyRecordListener {

}
}

/**
* Navigates to the Settings UI (primarily for the user to change the scan rate)
*/
fun navigateToSettings() {
findNavController().navigate(WifiDetailsFragmentDirections.actionWifiDetailsToSettings())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,12 @@ public class SurveyRecordProcessor
public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss").withZone(ZoneId.systemDefault());
private static final String MISSION_ID_PREFIX = "NS ";
private static final int UNSET_TX_POWER_LEVEL = 127;

/**
* It seems that every once in a while the RSSI value for a bluetooth record will be set to 127.
* I'm not sure why this is, but we will just ignore those records.
*/
private static final int UNSET_RSSI = 127;
private static final int MAX_CDR_LOCATION_WAIT_TIME = 5_000;

private final Object cellInfoProcessingLock = new Object();
Expand Down Expand Up @@ -1565,7 +1571,8 @@ private BluetoothRecord generateBluetoothSurveyRecord(BluetoothDevice device, in
dataBuilder.setRecordNumber(bluetoothRecordNumber++);

dataBuilder.setSourceAddress(sourceAddress);
if (txPowerLevel == UNSET_TX_POWER_LEVEL)

if (rssi != UNSET_RSSI)
{
dataBuilder.setSignalStrength(FloatValue.newBuilder().setValue(rssi).build());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ internal abstract class AChartDetailsViewModel : ViewModel() {

internal val modelProducer = CartesianChartModelProducer.build()

private val _scanRateSeconds = MutableStateFlow(-1)
val scanRate = _scanRateSeconds.asStateFlow()

// This is the RSSI that is displayed in the details header. It is not necessarily the same
// as the RSSI that is displayed in the chart because on the chart we have to limit the range
// of the RSSI values.
Expand Down Expand Up @@ -139,6 +142,13 @@ internal abstract class AChartDetailsViewModel : ViewModel() {

modelProducer.tryRunTransaction { add(lineLayerModelPartial) }
}

/**
* Sets the scan rate in seconds.
*/
fun setScanRateSeconds(scanRateSeconds: Int) {
_scanRateSeconds.value = scanRateSeconds
}
}

fun <E> dequeLimiter(limit: Int): ReadWriteProperty<Any?, ArrayDeque<E>> =
Expand Down
Loading

0 comments on commit 80790c0

Please sign in to comment.