Fixed concurrent modification crash in ServiceRecordAggregator and link clicking in scroll.

This commit is contained in:
Koen J 2024-12-12 14:13:24 +01:00
parent 4981617f7a
commit 6da5c11731
3 changed files with 56 additions and 45 deletions

View File

@ -55,6 +55,7 @@ class ServiceRecordAggregator {
if (_cts != null) throw Exception("Already started.") if (_cts != null) throw Exception("Already started.")
_cts = CoroutineScope(Dispatchers.Default).launch { _cts = CoroutineScope(Dispatchers.Default).launch {
try {
while (isActive) { while (isActive) {
val now = Date() val now = Date()
synchronized(_currentServices) { synchronized(_currentServices) {
@ -71,6 +72,9 @@ class ServiceRecordAggregator {
onServicesUpdated?.invoke(_currentServices.toList()) onServicesUpdated?.invoke(_currentServices.toList())
delay(5000) delay(5000)
} }
} catch (e: Throwable) {
Logger.e(TAG, "Unexpected failure in MDNS loop", e)
}
} }
} }
} }
@ -83,6 +87,7 @@ class ServiceRecordAggregator {
} }
fun add(packet: DnsPacket) { fun add(packet: DnsPacket) {
val currentServices: List<DnsService>
val dnsResourceRecords = packet.answers + packet.additionals + packet.authorities val dnsResourceRecords = packet.answers + packet.additionals + packet.authorities
val txtRecords = dnsResourceRecords.filter { it.type == ResourceRecordType.TXT.value.toInt() }.map { it to it.getDataReader().readTXTRecord() } val txtRecords = dnsResourceRecords.filter { it.type == ResourceRecordType.TXT.value.toInt() }.map { it to it.getDataReader().readTXTRecord() }
val aRecords = dnsResourceRecords.filter { it.type == ResourceRecordType.A.value.toInt() }.map { it to it.getDataReader().readARecord() } val aRecords = dnsResourceRecords.filter { it.type == ResourceRecordType.A.value.toInt() }.map { it to it.getDataReader().readARecord() }
@ -99,7 +104,7 @@ class ServiceRecordAggregator {
aaaaRecords.forEach { builder.appendLine("AAAA ${it.first.name} ${it.first.type} ${it.first.clazz} TTL ${it.first.timeToLive}: ${it.second.address}") } aaaaRecords.forEach { builder.appendLine("AAAA ${it.first.name} ${it.first.type} ${it.first.clazz} TTL ${it.first.timeToLive}: ${it.second.address}") }
Logger.i(TAG, "$builder")*/ Logger.i(TAG, "$builder")*/
val currentServices: MutableList<DnsService> synchronized(this._currentServices) {
ptrRecords.forEach { record -> ptrRecords.forEach { record ->
val cachedPtrRecord = _cachedPtrRecords.getOrPut(record.first.name) { mutableListOf() } val cachedPtrRecord = _cachedPtrRecords.getOrPut(record.first.name) { mutableListOf() }
val newPtrRecord = CachedDnsPtrRecord(Date(System.currentTimeMillis() + record.first.timeToLive.toLong() * 1000L), record.second.domainName) val newPtrRecord = CachedDnsPtrRecord(Date(System.currentTimeMillis() + record.first.timeToLive.toLong() * 1000L), record.second.domainName)
@ -126,8 +131,6 @@ class ServiceRecordAggregator {
_cachedSrvRecords[srvRecord.first.name] = CachedDnsSrvRecord(Date(System.currentTimeMillis() + srvRecord.first.timeToLive.toLong() * 1000L), srvRecord.second) _cachedSrvRecords[srvRecord.first.name] = CachedDnsSrvRecord(Date(System.currentTimeMillis() + srvRecord.first.timeToLive.toLong() * 1000L), srvRecord.second)
} }
//TODO: Maybe this can be debounced?
synchronized(this._currentServices) {
currentServices = getCurrentServices() currentServices = getCurrentServices()
this._currentServices.clear() this._currentServices.clear()
this._currentServices.addAll(currentServices) this._currentServices.addAll(currentServices)

View File

@ -59,7 +59,7 @@ class PlatformLinkMovementMethod(private val _context: Context) : LinkMovementMe
if (linkPressed && pressedLinks != null) { if (linkPressed && pressedLinks != null) {
val dx = event.x - downX val dx = event.x - downX
val dy = event.y - downY val dy = event.y - downY
if (Math.abs(dx) <= touchSlop && Math.abs(dy) <= touchSlop) { if (Math.abs(dx) <= touchSlop && Math.abs(dy) <= touchSlop && isTouchInside(widget, event)) {
runBlocking { runBlocking {
for (link in pressedLinks!!) { for (link in pressedLinks!!) {
Logger.i(TAG) { "Link clicked '${link.url}'." } Logger.i(TAG) { "Link clicked '${link.url}'." }
@ -101,7 +101,7 @@ class PlatformLinkMovementMethod(private val _context: Context) : LinkMovementMe
} }
} }
return super.onTouchEvent(widget, buffer, event) return false
} }
private fun findLinksAtTouchPosition(widget: TextView, buffer: Spannable, event: MotionEvent): Array<URLSpan> { private fun findLinksAtTouchPosition(widget: TextView, buffer: Spannable, event: MotionEvent): Array<URLSpan> {
@ -114,6 +114,10 @@ class PlatformLinkMovementMethod(private val _context: Context) : LinkMovementMe
return buffer.getSpans(off, off, URLSpan::class.java) return buffer.getSpans(off, off, URLSpan::class.java)
} }
private fun isTouchInside(widget: TextView, event: MotionEvent): Boolean {
return event.x >= 0 && event.x <= widget.width && event.y >= 0 && event.y <= widget.height
}
companion object { companion object {
const val TAG = "PlatformLinkMovementMethod" const val TAG = "PlatformLinkMovementMethod"
} }

View File

@ -76,7 +76,7 @@ class NonScrollingTextView : androidx.appcompat.widget.AppCompatTextView {
if (linkPressed && _lastTouchedLinks != null) { if (linkPressed && _lastTouchedLinks != null) {
val dx = event.x - downX val dx = event.x - downX
val dy = event.y - downY val dy = event.y - downY
if (Math.abs(dx) <= touchSlop && Math.abs(dy) <= touchSlop) { if (Math.abs(dx) <= touchSlop && Math.abs(dy) <= touchSlop && isTouchInside(event)) {
runBlocking { runBlocking {
for (link in _lastTouchedLinks!!) { for (link in _lastTouchedLinks!!) {
Logger.i(PlatformLinkMovementMethod.TAG) { "Link clicked '${link.url}'." } Logger.i(PlatformLinkMovementMethod.TAG) { "Link clicked '${link.url}'." }
@ -119,7 +119,11 @@ class NonScrollingTextView : androidx.appcompat.widget.AppCompatTextView {
} }
} }
return super.onTouchEvent(event) return false
}
private fun isTouchInside(event: MotionEvent): Boolean {
return event.x >= 0 && event.x <= width && event.y >= 0 && event.y <= height
} }
companion object { companion object {