Skip to content

Commit fd9c32d

Browse files
committed
Update MainActivity.kt
1 parent 2396018 commit fd9c32d

File tree

1 file changed

+126
-124
lines changed
  • display-device-location-with-nmea-data-sources/src/main/java/com/esri/arcgismaps/sample/displaydevicelocationwithnmeadatasources

1 file changed

+126
-124
lines changed

display-device-location-with-nmea-data-sources/src/main/java/com/esri/arcgismaps/sample/displaydevicelocationwithnmeadatasources/MainActivity.kt

Lines changed: 126 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ import com.arcgismaps.mapping.Viewpoint
3838
import com.esri.arcgismaps.sample.displaydevicelocationwithnmeadatasources.databinding.ActivityMainBinding
3939
import com.google.android.material.floatingactionbutton.FloatingActionButton
4040
import com.google.android.material.snackbar.Snackbar
41-
import kotlinx.coroutines.Dispatchers
4241
import kotlinx.coroutines.launch
4342
import java.io.BufferedReader
4443
import java.io.File
@@ -62,7 +61,10 @@ class MainActivity : AppCompatActivity() {
6261
// create a timer to simulate a stream of NMEA data
6362
private var timer = Timer()
6463

65-
// index of list of locations
64+
// list of nmea location sentences
65+
private var nmeaSentences: MutableList<String>? = null
66+
67+
// index of nmea location sentence
6668
private var locationIndex = 0
6769

6870
// set up data binding for the activity
@@ -113,114 +115,81 @@ class MainActivity : AppCompatActivity() {
113115
)
114116
)
115117

116-
// set the NMEA location data source onto the map view's location display
118+
// set the nmea location data source onto the map view's location display
117119
val locationDisplay = mapView.locationDisplay
118120
locationDisplay.dataSource = nmeaLocationDataSource
119121
locationDisplay.setAutoPanMode(LocationDisplayAutoPanMode.Recenter)
120122

121123
// disable map view interaction, the location display will automatically center on the mock device location
122124
mapView.interactionOptions.isPanEnabled = false
123125
mapView.interactionOptions.isZoomEnabled = false
126+
127+
// read nmea location sentences from file
128+
nmeaSentences = getNMEASentenceList()
129+
// collects the accuracy for each location change
130+
collectLocationChanges()
131+
// collects satellite changes and display satellite information
132+
setupSatelliteChangedListener()
124133
}
125134

126135
/**
127-
* Control the start/stop status of the NMEA location data source
136+
* Reads NMEA location sentences from the .nmea file and
137+
* returns it as a [MutableList]
128138
*/
129-
fun playPauseClick(view: View) {
130-
lifecycleScope.launch {
131-
if (nmeaLocationDataSource.status.value != LocationDataSourceStatus.Started) {
132-
// start location data source
133-
startNMEALocationDataSource()
134-
setButtonStatus(true)
135-
} else {
136-
// stop receiving and displaying location data
137-
nmeaLocationDataSource.stop().onSuccess {
138-
nmeaLocationDataSource = NmeaLocationDataSource(SpatialReference.wgs84())
139-
mapView.locationDisplay.dataSource = nmeaLocationDataSource
140-
}
141-
setButtonStatus(false)
142-
clearInformation()
139+
private fun getNMEASentenceList(): MutableList<String>? {
140+
// create list of nmea location sentences
141+
val nmeaSentences: MutableList<String> = mutableListOf()
142+
val simulatedNmeaDataFile = File("$provisionPath/Redlands.nmea")
143+
if (!simulatedNmeaDataFile.exists()) {
144+
showError("NMEA file does not exist")
145+
return null
146+
}
147+
// read the nmea file contents using a buffered reader and store the mock data sentences in a list
148+
return try {
149+
// create a buffered reader using the .nmea file
150+
val bufferedReader = BufferedReader(FileReader(simulatedNmeaDataFile.path))
151+
var line = bufferedReader.readLine()
152+
while (line != null) {
153+
// add carriage return for nmea location data source parser
154+
nmeaSentences.add(line + "\n")
155+
line = bufferedReader.readLine()
143156
}
157+
bufferedReader.close()
158+
nmeaSentences
159+
} catch (e: Exception) {
160+
showError("Error creating NMEA sentences " + e.message)
161+
null
144162
}
145163
}
146164

147165
/**
148-
* Sets the FAB button to "Start"/"Stop" based on [isShowingLocation]
166+
* Control the start/stop status of the NMEA location data source
149167
*/
150-
private fun setButtonStatus(isShowingLocation: Boolean) = if (isShowingLocation) {
151-
playPauseFAB.setImageDrawable(
152-
AppCompatResources.getDrawable(
153-
this, R.drawable.ic_round_pause_24
154-
)
155-
)
156-
} else {
157-
playPauseFAB.setImageDrawable(
158-
AppCompatResources.getDrawable(
159-
this, R.drawable.ic_round_play_arrow_24
160-
)
161-
)
168+
fun playPauseClick(view: View) = lifecycleScope.launch {
169+
if (nmeaLocationDataSource.status.value != LocationDataSourceStatus.Started) {
170+
// initialize the location data source and prepare to begin receiving location updates when data is pushed
171+
// as updates are received, they will be displayed on the map
172+
nmeaLocationDataSource.start().onFailure {
173+
showError("NmeaLocationDataSource failed to start: ${it.message}")
174+
}
175+
// starts the NMEA mock data sentences
176+
nmeaSentences?.let { startNMEAMockData(it) }
177+
setButtonStatus(true)
178+
} else {
179+
// stop receiving and displaying location data
180+
nmeaLocationDataSource.stop()
181+
// cancel up the timer task
182+
timer.cancel()
183+
setButtonStatus(false)
184+
clearInformation()
185+
}
162186
}
163187

164188
/**
165189
* Initializes the location data source, reads the mock data NMEA sentences, and displays location updates from that file
166190
* on the location display. Data is pushed to the data source using a timeline to simulate live updates, as they would
167191
* appear if using real-time data from a GPS dongle
168192
*/
169-
private fun startNMEALocationDataSource() {
170-
val simulatedNmeaDataFile = File("$provisionPath/Redlands.nmea")
171-
if (simulatedNmeaDataFile.exists()) {
172-
try {
173-
// read the nmea file contents using a buffered reader and store the mock data sentences in a list
174-
val bufferedReader = BufferedReader(FileReader(simulatedNmeaDataFile.path))
175-
// add carriage return for NMEA location data source parser
176-
val nmeaSentences: MutableList<String> = mutableListOf()
177-
var line = bufferedReader.readLine()
178-
while (line != null) {
179-
nmeaSentences.add(line + "\n")
180-
line = bufferedReader.readLine()
181-
}
182-
bufferedReader.close()
183-
184-
lifecycleScope.apply {
185-
launch {
186-
// initialize the location data source and prepare to begin receiving location updates when data is pushed
187-
// as updates are received, they will be displayed on the map
188-
nmeaLocationDataSource.start()
189-
}
190-
launch {
191-
// collect the accuracy for each location change
192-
nmeaLocationDataSource.locationChanged.collect {
193-
// convert from meters to foot
194-
val horizontalAccuracy = it.horizontalAccuracy * 3.28084
195-
val verticalAccuracy = it.verticalAccuracy * 3.28084
196-
accuracyTV.text =
197-
getString(R.string.accuracy) + "Horizontal-%.1fft, Vertical-%.1fft".format(
198-
horizontalAccuracy, verticalAccuracy
199-
)
200-
}
201-
}
202-
launch {
203-
// handle when LocationDataSource status is changed
204-
nmeaLocationDataSource.status.collect {
205-
if (it == LocationDataSourceStatus.Started) {
206-
// add a satellite changed listener to the NMEA location data source and display satellite information
207-
setupSatelliteChangedListener()
208-
// starts the NMEA mock data sentences
209-
startNMEAMockData(nmeaSentences)
210-
}
211-
if (it == LocationDataSourceStatus.Stopped) {
212-
timer.cancel()
213-
}
214-
}
215-
}
216-
}
217-
} catch (e: Exception) {
218-
showError("Error while setting up NmeaLocationDataSource: " + e.message)
219-
}
220-
} else {
221-
showError("NMEA File not found")
222-
}
223-
}
224193

225194
/**
226195
* Push the mock data NMEA sentences into the data source every 250 ms
@@ -240,49 +209,82 @@ class MainActivity : AppCompatActivity() {
240209
}
241210

242211
/**
243-
* Obtains NMEA satellite information from the NMEA location data source, and displays satellite information on the app
212+
* Sets the FAB button to "Start"/"Stop" based on [isShowingLocation]
213+
*/
214+
private fun setButtonStatus(isShowingLocation: Boolean) = if (isShowingLocation) {
215+
playPauseFAB.setImageDrawable(
216+
AppCompatResources.getDrawable(
217+
this, R.drawable.ic_round_pause_24
218+
)
219+
)
220+
} else {
221+
playPauseFAB.setImageDrawable(
222+
AppCompatResources.getDrawable(
223+
this, R.drawable.ic_round_play_arrow_24
224+
)
225+
)
226+
}
227+
228+
/**
229+
* Collects location changes of the NMEA location data source,
230+
* and displays the location accuracy
231+
*/
232+
private fun collectLocationChanges() = lifecycleScope.launch {
233+
nmeaLocationDataSource.locationChanged.collect { nmeaLocation ->
234+
// convert from meters to foot
235+
val horizontalAccuracy = nmeaLocation.horizontalAccuracy * 3.28084
236+
val verticalAccuracy = nmeaLocation.verticalAccuracy * 3.28084
237+
accuracyTV.text =
238+
getString(R.string.accuracy) + "Horizontal-%.1fft, Vertical-%.1fft".format(
239+
horizontalAccuracy, verticalAccuracy
240+
)
241+
}
242+
}
243+
244+
/**
245+
* Obtains NMEA satellite information from the NMEA location data source,
246+
* and displays satellite information on the app
244247
*/
245-
private fun setupSatelliteChangedListener() {
246-
lifecycleScope.launch {
247-
nmeaLocationDataSource.satellitesChanged.collect { nmeaSatelliteInfoList ->
248-
val uniqueSatelliteIDs = mutableListOf<Int>()
249-
var satelliteSystems = ""
250-
// set the text of the satellite count label
251-
satelliteCountTV.text =
252-
getString(R.string.satellite_count) + nmeaSatelliteInfoList.size
253-
// get the system of the first satellite
254-
when (nmeaSatelliteInfoList.first().system) {
255-
NmeaGnssSystem.Bds -> {
256-
satelliteSystems = "BDS"
257-
}
258-
NmeaGnssSystem.Galileo -> {
259-
satelliteSystems = "Galileo"
260-
}
261-
NmeaGnssSystem.Glonass -> {
262-
satelliteSystems = "Glonass"
263-
}
264-
NmeaGnssSystem.Gps -> {
265-
satelliteSystems = "GPS"
266-
}
267-
NmeaGnssSystem.NavIc -> {
268-
satelliteSystems = "NavIc"
269-
}
270-
NmeaGnssSystem.Qzss -> {
271-
satelliteSystems = "Qzss"
272-
}
273-
NmeaGnssSystem.Unknown -> {
274-
satelliteSystems = "Unknown"
275-
}
248+
private fun setupSatelliteChangedListener() = lifecycleScope.launch {
249+
nmeaLocationDataSource.satellitesChanged.collect { nmeaSatelliteInfoList ->
250+
val uniqueSatelliteIDs = mutableListOf<Int>()
251+
var satelliteSystems = ""
252+
// set the text of the satellite count label
253+
satelliteCountTV.text =
254+
getString(R.string.satellite_count) + nmeaSatelliteInfoList.size
255+
// get the system of the first satellite
256+
when (nmeaSatelliteInfoList.first().system) {
257+
NmeaGnssSystem.Bds -> {
258+
satelliteSystems = "BDS"
276259
}
277-
// get the satellite IDs from the info list
278-
nmeaSatelliteInfoList.forEach { satelliteInfo ->
279-
uniqueSatelliteIDs.add(satelliteInfo.id)
260+
NmeaGnssSystem.Galileo -> {
261+
satelliteSystems = "Galileo"
280262
}
281-
// display the satellite system and id information
282-
systemTypeTV.text = getString(R.string.system) + satelliteSystems
283-
satelliteIDsTV.text = getString(R.string.satellite_ids) + uniqueSatelliteIDs
263+
NmeaGnssSystem.Glonass -> {
264+
satelliteSystems = "Glonass"
265+
}
266+
NmeaGnssSystem.Gps -> {
267+
satelliteSystems = "GPS"
268+
}
269+
NmeaGnssSystem.NavIc -> {
270+
satelliteSystems = "NavIc"
271+
}
272+
NmeaGnssSystem.Qzss -> {
273+
satelliteSystems = "Qzss"
274+
}
275+
NmeaGnssSystem.Unknown -> {
276+
satelliteSystems = "Unknown"
277+
}
278+
}
279+
// get the satellite IDs from the info list
280+
nmeaSatelliteInfoList.forEach { satelliteInfo ->
281+
uniqueSatelliteIDs.add(satelliteInfo.id)
284282
}
283+
// display the satellite system and id information
284+
systemTypeTV.text = getString(R.string.system) + satelliteSystems
285+
satelliteIDsTV.text = getString(R.string.satellite_ids) + uniqueSatelliteIDs
285286
}
287+
286288
}
287289

288290
/**

0 commit comments

Comments
 (0)