Workaround duplicated onPrimaryClipChanged callback

This commit is contained in:
Rocka 2024-12-07 16:57:21 +08:00
parent 6df7260544
commit 8dc7304c68
No known key found for this signature in database
GPG Key ID: 28031158FFDD6853
3 changed files with 58 additions and 24 deletions

View File

@ -6,10 +6,10 @@ package org.fcitx.fcitx5.android.data.clipboard
import android.content.ClipboardManager
import android.content.Context
import android.os.Build
import androidx.annotation.Keep
import androidx.room.Room
import androidx.room.withTransaction
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
@ -147,33 +147,50 @@ object ClipboardManager : ClipboardManager.OnPrimaryClipChangedListener,
}
}
private var lastClipTimestamp = -1L
private var lastClipHash = 0
override fun onPrimaryClipChanged() {
clipboardManager.primaryClip
?.let { ClipboardEntry.fromClipData(it, transformer) }
?.takeIf { it.text.isNotBlank() }
?.let { e ->
val handler = CoroutineExceptionHandler { _, exception ->
Timber.w("Failed to update clipboard database: $exception")
updateLastEntry(e)
}
launch(handler) {
mutex.withLock {
clbDao.find(e.text, e.sensitive)?.let {
updateLastEntry(it.copy(timestamp = e.timestamp))
clbDao.updateTime(it.id, e.timestamp)
return@launch
}
val insertedEntry = clbDb.withTransaction {
val rowId = clbDao.insert(e)
removeOutdated()
// new entry can be deleted immediately if clipboard limit == 0
clbDao.get(rowId) ?: e
}
updateLastEntry(insertedEntry)
updateItemCount()
val clip = clipboardManager.primaryClip ?: return
/**
* skip duplicate ClipData
* https://developer.android.com/reference/android/content/ClipboardManager.OnPrimaryClipChangedListener#onPrimaryClipChanged()
*/
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val timestamp = clip.description.timestamp
if (timestamp == lastClipTimestamp) return
lastClipTimestamp = timestamp
} else {
val timestamp = System.currentTimeMillis()
val hash = clip.hashCode()
if (timestamp - lastClipTimestamp < 100L && hash == lastClipHash) return
lastClipTimestamp = timestamp
lastClipHash = hash
}
launch {
mutex.withLock {
val entry = ClipboardEntry.fromClipData(clip, transformer) ?: return@withLock
if (entry.text.isBlank()) return@withLock
try {
clbDao.find(entry.text, entry.sensitive)?.let {
updateLastEntry(it.copy(timestamp = entry.timestamp))
clbDao.updateTime(it.id, entry.timestamp)
return@withLock
}
val insertedEntry = clbDb.withTransaction {
val rowId = clbDao.insert(entry)
removeOutdated()
// new entry can be deleted immediately if clipboard limit == 0
clbDao.get(rowId) ?: entry
}
updateLastEntry(insertedEntry)
updateItemCount()
} catch (exception: Exception) {
Timber.w("Failed to update clipboard database: $exception")
updateLastEntry(entry)
}
}
}
}
private suspend fun removeOutdated() {

View File

@ -10,6 +10,7 @@ import android.os.Build
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import org.fcitx.fcitx5.android.utils.timestamp
@Entity(tableName = ClipboardEntry.TABLE_NAME)
data class ClipboardEntry(
@ -52,6 +53,7 @@ data class ClipboardEntry(
}
return ClipboardEntry(
text = if (transformer != null) transformer(str) else str,
timestamp = clipData.timestamp(),
type = desc.getMimeType(0),
sensitive = sensitive
)

View File

@ -0,0 +1,15 @@
/*
* SPDX-License-Identifier: LGPL-2.1-or-later
* SPDX-FileCopyrightText: Copyright 2024 Fcitx5 for Android Contributors
*/
package org.fcitx.fcitx5.android.utils
import android.content.ClipData
import android.os.Build
fun ClipData.timestamp() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
description.timestamp
} else {
System.currentTimeMillis()
}