Реализовать пользовательское контекстное меню копирование / вставка / выберите все функциональность в WebView AndroidAndroid

Форум для тех, кто программирует под Android
Ответить Пред. темаСлед. тема
Anonymous
 Реализовать пользовательское контекстное меню копирование / вставка / выберите все функциональность в WebView Android

Сообщение Anonymous »

Я внедряю пользовательский буферизатор, который не разрешает операцию копирования / вставки из других приложений. Текст, скопированный в приложении, может быть вставлен только в приложение. Пожалуйста, помогите мне с пользовательским веб -просмотром, чтобы я мог получить обратный вызов для вырезания / копирования / вставки из текста в 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
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Почему контекстное меню GtkText (копирование, вставка) перестает работать; Если граница CSS применяется к GtkText?
    Anonymous » » в форуме CSS
    0 Ответы
    16 Просмотры
    Последнее сообщение Anonymous
  • Пользовательское копирование и вставка сетки данных WPF
    Anonymous » » в форуме C#
    0 Ответы
    6 Просмотры
    Последнее сообщение Anonymous
  • Пользовательское копирование/вставка сетки данных WPF
    Anonymous » » в форуме C#
    0 Ответы
    9 Просмотры
    Последнее сообщение Anonymous
  • Пользовательское копирование и вставка сетки данных WPF
    Anonymous » » в форуме C#
    0 Ответы
    11 Просмотры
    Последнее сообщение Anonymous
  • Строка меню UIMenuBuilder и контекстное меню
    Anonymous » » в форуме IOS
    0 Ответы
    54 Просмотры
    Последнее сообщение Anonymous

Вернуться в «Android»