Skip to content

Commit

Permalink
Reduce number of clipboard synchronizations
Browse files Browse the repository at this point in the history
- VncClient will ignore repeated requests to sync clipboard with same text.
  This happens due to activity lifecycle.
- VncViewModel will drop new clip texts from server while previous text
  is being processed. This should prevent some ANRs.
  • Loading branch information
gujjwal00 committed Feb 22, 2024
1 parent 971f9ac commit 22f3ddd
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 6 deletions.
14 changes: 13 additions & 1 deletion app/src/main/java/com/gaurav/avnc/viewmodel/VncViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import com.gaurav.avnc.vnc.Messenger
import com.gaurav.avnc.vnc.UserCredential
import com.gaurav.avnc.vnc.VncClient
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
Expand Down Expand Up @@ -318,8 +319,19 @@ class VncViewModel(val profile: ServerProfile, app: Application) : BaseViewModel
}
}

private var clipReceiverJob: Job? = null
private fun receiveClipboardText(text: String) {
if (pref.server.clipboardSync) launchIO {
if (!pref.server.clipboardSync)
return

// This is a protective measure against servers which send every 'selection' made on the server.
// Setting clip text involves IPC, so these events can exhaust Binder resources, leading to ANRs.
if (clipReceiverJob?.isActive == true) {
Log.w(javaClass.simpleName, "Dropping clip text received from server, previous text is still pending")
return
}

clipReceiverJob = launchIO {
setClipboardText(app, text)
}
}
Expand Down
24 changes: 19 additions & 5 deletions app/src/main/java/com/gaurav/avnc/vnc/VncClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ class VncClient(private val observer: Observer) {
private var autoFBRequestsQueued = true
private var autoFBRequests = autoFBRequestsQueued

/**
* Value of the most recent cut text sent/received from server
*/
@Volatile
private var lastCutText: String? = null

/**
* Setup different properties for this client.
*
Expand Down Expand Up @@ -195,10 +201,14 @@ class VncClient(private val observer: Observer) {
* Sends text to remote desktop's clipboard.
*/
fun sendCutText(text: String) = ifConnectedAndInteractive {
if (nativeIsUTF8CutTextSupported(nativePtr))
nativeSendCutText(nativePtr, text.toByteArray(StandardCharsets.UTF_8), true)
else
nativeSendCutText(nativePtr, text.toByteArray(StandardCharsets.ISO_8859_1), false)
if (text != lastCutText) {
val sent = if (nativeIsUTF8CutTextSupported(nativePtr))
nativeSendCutText(nativePtr, text.toByteArray(StandardCharsets.UTF_8), true)
else
nativeSendCutText(nativePtr, text.toByteArray(StandardCharsets.ISO_8859_1), false)
if (sent)
lastCutText = text
}
}

/**
Expand Down Expand Up @@ -294,7 +304,11 @@ class VncClient(private val observer: Observer) {
@Keep
private fun cbGotXCutText(bytes: ByteArray, isUTF8: Boolean) {
(if (isUTF8) StandardCharsets.UTF_8 else StandardCharsets.ISO_8859_1).let {
observer.onGotXCutText(it.decode(ByteBuffer.wrap(bytes)).toString())
val cutText = it.decode(ByteBuffer.wrap(bytes)).toString()
if (cutText != lastCutText) {
lastCutText = cutText
observer.onGotXCutText(cutText)
}
}
}

Expand Down

0 comments on commit 22f3ddd

Please sign in to comment.