Я внедряю пользовательский буферизатор, который не разрешает операцию копирования / вставки из других приложений. Текст, скопированный в приложении, может быть вставлен только в приложение. Пожалуйста, помогите мне с пользовательским веб -просмотром, чтобы я мог получить обратный вызов для вырезания / копирования / вставки из текста в WebView. WebView может иметь редактируемый контент или не редактируемый контент. WebView не предоставляет обратный вызов для операций вырезания /копирования /вставки < /p>
secureTextView < /p>
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.os.Build
import android.util.AttributeSet
import android.view.ActionMode
import android.view.Menu
import android.view.MenuItem
import android.widget.Toast
import androidx.appcompat.widget.AppCompatTextView
class SecureTextView : AppCompatTextView {
constructor(context: Context) : super(context) { init() }
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { init() }
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { init() }
private fun init() {
if (SecureClipboardConfig.isEnabled) {
setupCustomActionMode()
setTextIsSelectable(true)
}
}
private fun setupCustomActionMode() {
customSelectionActionModeCallback = object : ActionMode.Callback {
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
menu?.clear()
// Show custom copy action if text is selected
if (hasSelection()) {
menu?.add(0, MENU_COPY, 0, "Copy")?.apply {
setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
}
}
menu?.add(0, MENU_SELECT_ALL, 1, "Select All")?.apply {
setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER)
}
return true
}
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
menu?.findItem(MENU_COPY)?.isVisible = hasSelection()
return true
}
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
when (item?.itemId) {
MENU_COPY -> {
performInternalCopy()
mode?.finish()
return true
}
MENU_SELECT_ALL -> {
performSelectAll()
return true
}
}
return false
}
override fun onDestroyActionMode(mode: ActionMode?) {}
}
// Handle insertion action mode (when cursor is positioned without selection from suggestion strip in keyboard)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
customInsertionActionModeCallback = object : ActionMode.Callback {
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
menu?.clear()
menu?.add(0, MENU_SELECT_ALL, 0, "Select All")?.apply {
setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER)
}
return true
}
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
return true
}
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
when (item?.itemId) {
MENU_SELECT_ALL -> {
performSelectAll()
return true
}
}
return false
}
override fun onDestroyActionMode(mode: ActionMode?) {}
}
}
}
private fun performInternalCopy() {
val selectedText = getSelectedText()
if (selectedText.isNotEmpty()) {
InternalClipboardManager.copy(selectedText)
Toast.makeText(context, "Copied to internal clipboard", Toast.LENGTH_SHORT).show()
// Clear system clipboard to prevent external access
clearSystemClipboard()
}
}
private fun performSelectAll() {
val textLength = text?.length ?: 0
if (textLength > 0) {
if (text is android.text.Spannable) {
android.text.Selection.setSelection(text as android.text.Spannable, 0, textLength)
}
}
}
private fun clearSystemClipboard() {
/* try {
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText("", "")
clipboard.setPrimaryClip(clip)
} catch (e: Exception) {
// Handle exception silently
}*/
}
private fun getSelectedText(): String {
val start = selectionStart
val end = selectionEnd
return if (start >= 0 && end >= 0 && start != end) {
text?.substring(start, end) ?: ""
} else {
""
}
}
override fun hasSelection(): Boolean {
return selectionStart != selectionEnd && selectionStart >= 0
}
// Override system clipboard operations
override fun onTextContextMenuItem(id: Int): Boolean {
return when (id) {
android.R.id.copy -> {
if (SecureClipboardConfig.isEnabled) {
performInternalCopy()
true
} else {
super.onTextContextMenuItem(id)
}
}
android.R.id.selectAll -> {
if (SecureClipboardConfig.isEnabled) {
performSelectAll()
true
} else {
super.onTextContextMenuItem(id)
}
}
// Block paste operations entirely for TextView since it's read-only
android.R.id.paste -> {
if (SecureClipboardConfig.isEnabled) {
Toast.makeText(context, "Paste not available for text view", Toast.LENGTH_SHORT).show()
true
} else {
super.onTextContextMenuItem(id)
}
}
else -> super.onTextContextMenuItem(id)
}
}
// Override long click to ensure our custom action mode is used
override fun performLongClick(): Boolean {
if (SecureClipboardConfig.isEnabled) {
return super.performLongClick()
}
return super.performLongClick()
}
companion object {
private const val MENU_COPY = 1
private const val MENU_SELECT_ALL = 2
}
}
< /code>
InternalClipboardmanager < /p>
import android.content.Context
import android.content.SharedPreferences
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
object InternalClipboardManager {
private var internalClipboard: String = ""
private var clipboardData = mutableMapOf()
private val listeners = mutableListOf()
private var sharedPrefs: SharedPreferences? = null
private val gson = Gson()
private const val PREFS_NAME = "internal_clipboard_prefs"
private const val KEY_CLIPBOARD_TEXT = "clipboard_text"
private const val KEY_CLIPBOARD_DATA = "clipboard_data"
interface ClipboardChangeListener {
fun onClipboardChanged(data: String)
}
fun init(context: Context) {
sharedPrefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
loadFromPrefs()
}
fun copy(text: String) {
internalClipboard = text
saveToPrefs()
notifyListeners(text)
}
fun paste(): String {
return internalClipboard
}
fun hasData(): Boolean {
return internalClipboard.isNotEmpty()
}
fun clear() {
internalClipboard = ""
clipboardData.clear()
saveToPrefs()
notifyListeners("")
}
// Support for rich data
fun copyData(key: String, data: Any) {
clipboardData[key] = data
saveToPrefs()
}
fun getData(key: String): Any? {
return clipboardData[key]
}
fun addListener(listener: ClipboardChangeListener) {
listeners.add(listener)
}
fun removeListener(listener: ClipboardChangeListener) {
listeners.remove(listener)
}
private fun notifyListeners(data: String) {
listeners.forEach { it.onClipboardChanged(data) }
}
private fun saveToPrefs() {
sharedPrefs?.let { prefs ->
val editor = prefs.edit()
// Save text clipboard
editor.putString(KEY_CLIPBOARD_TEXT, internalClipboard)
// Save rich data as JSON
try {
val jsonData = gson.toJson(clipboardData)
editor.putString(KEY_CLIPBOARD_DATA, jsonData)
} catch (e: Exception) {
// Handle serialization error
editor.putString(KEY_CLIPBOARD_DATA, "{}")
}
editor.apply()
}
}
private fun loadFromPrefs() {
sharedPrefs?.let { prefs ->
// Load text clipboard
internalClipboard = prefs.getString(KEY_CLIPBOARD_TEXT, "") ?: ""
// Load rich data from JSON
try {
val jsonData = prefs.getString(KEY_CLIPBOARD_DATA, "{}")
val type = object : TypeToken() {}.type
val loadedData: MutableMap = gson.fromJson(jsonData, type) ?: mutableMapOf()
clipboardData.clear()
clipboardData.putAll(loadedData)
} catch (e: Exception) {
// Handle deserialization error
clipboardData.clear()
}
}
}
}
Подробнее здесь: https://stackoverflow.com/questions/796 ... in-webview
Реализовать пользовательское контекстное меню копирование / вставка / выберите все функциональность в WebView Android ⇐ Android
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение