@@ -236,6 +236,7 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
236236 private var bypassObservationQueue: Boolean = false
237237 private var bypassMediaDeletedListener: Boolean = false
238238 private var bypassCrashPreventerInputFilter: Boolean = false
239+ private var overrideSamsungPredictiveBehavior: Boolean = false
239240
240241 var initialEditorContentParsedSHA256: ByteArray = ByteArray (0 )
241242
@@ -663,6 +664,29 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
663664 handleBackspaceAndEnter(event)
664665 }
665666
667+ // This InputFilter is creating for fixing the issue with predictive text on Samsung devices with API 33
668+ // (at least this time) https://github.com/wordpress-mobile/AztecEditor-Android/issues/1023
669+ // We are detecting when content of the editor is replaced with identical content, by comparing string values
670+ // and ranges of incoming and exiting content. When this happens, instead of using incoming source content
671+ // we use original content, with SuggestionSpan from incoming content added to it.
672+ val samsungContentReplacementPreventer = InputFilter { source, start, end, dest, dstart, dend ->
673+ var temp: CharSequence? = null
674+ if (overrideSamsungPredictiveBehavior) {
675+ val equalStringValues = source.toString() == dest.toString()
676+ val equalRange = start == 0 && dstart == 0 && end == source.length && dend == source.length
677+
678+
679+ if (equalStringValues && equalRange) {
680+ temp = SpannableStringBuilder (dest)
681+ TextUtils .copySpansFrom(dest, 0 , dest.length, Any ::class .java, temp, 0 )
682+ if (source is Spanned ) {
683+ TextUtils .copySpansFrom(source, 0 , dest.length, SuggestionSpan ::class .java, temp, 0 )
684+ }
685+ }
686+ }
687+ temp
688+ }
689+
666690 // This InputFilter created only for the purpose of avoiding crash described here:
667691 // https://android-review.googlesource.com/c/platform/frameworks/base/+/634929
668692 // https://github.com/wordpress-mobile/AztecEditor-Android/issues/729
@@ -723,11 +747,13 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
723747 source
724748 }
725749
726- if (Build .VERSION .SDK_INT == Build .VERSION_CODES .O || Build .VERSION .SDK_INT == Build .VERSION_CODES .O_MR1 ) {
750+ filters = if (Build .MANUFACTURER == " samsung" && Build .VERSION .SDK_INT == 33 ) {
751+ arrayOf(samsungContentReplacementPreventer, emptyEditTextBackspaceDetector)
752+ } else if (Build .VERSION .SDK_INT == Build .VERSION_CODES .O || Build .VERSION .SDK_INT == Build .VERSION_CODES .O_MR1 ) {
727753 // dynamicLayoutCrashPreventer needs to be first in array as these are going to be chained when processed
728- filters = arrayOf(dynamicLayoutCrashPreventer, emptyEditTextBackspaceDetector)
754+ arrayOf(dynamicLayoutCrashPreventer, emptyEditTextBackspaceDetector)
729755 } else {
730- filters = arrayOf(emptyEditTextBackspaceDetector)
756+ arrayOf(emptyEditTextBackspaceDetector)
731757 }
732758 }
733759
@@ -1713,6 +1739,14 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
17131739 bypassMediaDeletedListener = false
17141740 }
17151741
1742+ fun enableSamsungPredictiveBehaviorOverride () {
1743+ overrideSamsungPredictiveBehavior = true
1744+ }
1745+
1746+ fun disableSamsungPredictiveBehaviorOverride () {
1747+ overrideSamsungPredictiveBehavior = false
1748+ }
1749+
17161750 fun isMediaDeletedListenerDisabled (): Boolean {
17171751 return bypassMediaDeletedListener
17181752 }
@@ -1865,7 +1899,7 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
18651899 val html = Format .removeSourceEditorFormatting(parser.toHtml(output), isInCalypsoMode, isInGutenbergMode)
18661900
18671901 val clipboard = context.getSystemService(Context .CLIPBOARD_SERVICE ) as android.content.ClipboardManager
1868- clipboard.primaryClip = ClipData .newHtmlText(" aztec" , output.toString(), html)
1902+ clipboard.setPrimaryClip( ClipData .newHtmlText(" aztec" , output.toString(), html) )
18691903 }
18701904
18711905 // copied from TextView with some changes
@@ -1926,14 +1960,14 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
19261960 }
19271961 if (itemToPaste != null ) {
19281962 val oldHtml = toPlainHtml().replace(" <aztec_cursor>" , " " )
1929- val pastedHtmlText: String = plugins.filterIsInstance<IClipboardPastePlugin <* >>()
1963+ val pastedHtmlText: String = ( plugins.filterIsInstance<IClipboardPastePlugin <* >>()
19301964 .fold(null as ? String? ) { acc, plugin ->
19311965 plugin.itemToHtml(itemToPaste, acc ? : selectedText?.takeIf { it.isNotBlank() }) ? : acc
19321966 } ? : when (itemToPaste) {
19331967 is IClipboardPastePlugin .PastedItem .HtmlText -> itemToPaste.text
19341968 is IClipboardPastePlugin .PastedItem .Url -> itemToPaste.uri.path
19351969 is IClipboardPastePlugin .PastedItem .PastedIntent -> itemToPaste.intent.toString()
1936- }
1970+ }) !!
19371971
19381972 val newHtml = oldHtml.replace(
19391973 Constants .REPLACEMENT_MARKER_STRING ,
@@ -2083,7 +2117,7 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
20832117
20842118 unknownBlockSpanStart = text.getSpanStart(unknownHtmlSpan)
20852119 blockEditorDialog = builder.create()
2086- blockEditorDialog?.window?.setSoftInputMode(WindowManager .LayoutParams .SOFT_INPUT_ADJUST_RESIZE )
2120+ // blockEditorDialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
20872121 blockEditorDialog?.show()
20882122 }
20892123
0 commit comments