@@ -35,7 +35,6 @@ import android.os.Parcel
3535import android.os.Parcelable
3636import android.text.Editable
3737import android.text.InputFilter
38- import android.text.Selection
3938import android.text.Spannable
4039import android.text.SpannableStringBuilder
4140import android.text.Spanned
@@ -51,8 +50,8 @@ import android.view.View
5150import android.view.View.OnLongClickListener
5251import android.view.WindowManager
5352import android.view.inputmethod.BaseInputConnection
54- import android.view.inputmethod.CompletionInfo
55- import android.view.inputmethod.CorrectionInfo
53+ import android.view.inputmethod.EditorInfo
54+ import android.view.inputmethod.InputConnection
5655import android.widget.CheckBox
5756import android.widget.EditText
5857import android.widget.Toast
@@ -220,30 +219,6 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
220219 }
221220 }
222221
223- override fun onBeginBatchEdit () {
224- super .onBeginBatchEdit()
225- }
226-
227- override fun onEditorAction (actionCode : Int ) {
228- super .onEditorAction(actionCode)
229- }
230-
231- override fun onPrivateIMECommand (action : String? , data : Bundle ? ): Boolean {
232- return super .onPrivateIMECommand(action, data)
233- }
234-
235- override fun onKeyDown (keyCode : Int , event : KeyEvent ? ): Boolean {
236- return super .onKeyDown(keyCode, event)
237- }
238-
239- override fun onCommitCorrection (info : CorrectionInfo ? ) {
240- super .onCommitCorrection(info)
241- }
242-
243- override fun onCommitCompletion (text : CompletionInfo ? ) {
244- super .onCommitCompletion(text)
245- }
246-
247222 private val REGEXP_EMAIL = Regex (" ^[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,}$" ,
248223 setOf (RegexOption .DOT_MATCHES_ALL , RegexOption .IGNORE_CASE ))
249224 private val REGEXP_STANDALONE_URL = Regex (" ^(?:[a-z]+:|#|\\ ?|\\ .|/)" , RegexOption .DOT_MATCHES_ALL )
@@ -682,6 +657,15 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
682657 return super .onTouchEvent(event)
683658 }
684659
660+ override fun onCreateInputConnection (outAttrs : EditorInfo ): InputConnection {
661+ val baseInputConnection = requireNotNull(super .onCreateInputConnection(outAttrs))
662+ return if (Build .MANUFACTURER == " samsung" && Build .VERSION .SDK_INT == 33 && overrideSamsungPredictiveBehavior) {
663+ SamsungInputConnection (this , baseInputConnection)
664+ } else {
665+ baseInputConnection
666+ }
667+ }
668+
685669 // Setup the keyListener(s) for Backspace and Enter key.
686670 // Backspace: If listener does return false we remove the style here
687671 // Enter: Ask the listener if we need to insert or not the char
@@ -691,58 +675,6 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
691675 handleBackspaceAndEnter(event)
692676 }
693677
694- // This InputFilter is creating for fixing the issue with predictive text on Samsung devices with API 33
695- // (at least this time) https://github.com/wordpress-mobile/AztecEditor-Android/issues/1023
696- // We are detecting when content of the editor is replaced with identical content, by comparing string values
697- // and ranges of incoming and exiting content. When this happens, instead of using incoming source content
698- // we use original content, with SuggestionSpan from incoming content added to it.
699- val samsungContentReplacementPreventer = InputFilter { source, start, end, dest, dstart, dend ->
700- var temp: CharSequence? = null
701- if (overrideSamsungPredictiveBehavior) {
702- val equalStringValues = source.toString() == dest.toString()
703- val equalRange = start == 0 && dstart == 0 && end == source.length && dend == source.length
704-
705- if (equalStringValues && equalRange) {
706- overrideSamsungPredictiveBehavior = false
707- // we can't just return a dest, so we need to copy it into a new spannable string
708- // this will also strip all the internal "service" spans
709- temp = SpannableStringBuilder (dest)
710- // TextUtils.copySpansFrom(dest, 0, dest.length, Any::class.java, temp, 0)
711- // copy all the suggestion spans from the source, so we can see underlines
712- disableCrashPreventerInputFilter()
713- disableTextChangedListener()
714- disableMediaDeletedListener()
715-
716- if (source is Spanned ) {
717- TextUtils .copySpansFrom(source, 0 , dest.length, SuggestionSpan ::class .java, temp, 0 )
718- }
719-
720- val selStart = Selection .getSelectionStart(text)
721- val selEnd = Selection .getSelectionEnd(text)
722- val len = text.length
723-
724- text.clearSpans()
725- setTextKeepState(temp)
726-
727- if (selStart >= 0 || selEnd >= 0 ) {
728- Selection .setSelection(text,
729- Math .max(0 , Math .min(selStart, len)),
730- Math .max(0 , Math .min(selEnd, len)))
731- }
732-
733-
734- contentChangeWatcher.notifyContentChanged()
735-
736- temp = null
737- enableTextChangedListener()
738- enableMediaDeletedListener()
739- enableCrashPreventerInputFilter()
740- overrideSamsungPredictiveBehavior = true
741- }
742- }
743- temp
744- }
745-
746678 // This InputFilter created only for the purpose of avoiding crash described here:
747679 // https://android-review.googlesource.com/c/platform/frameworks/base/+/634929
748680 // https://github.com/wordpress-mobile/AztecEditor-Android/issues/729
@@ -803,16 +735,12 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
803735 source
804736 }
805737
806- filters =
807- if (Build .MANUFACTURER == " samsung" && Build .VERSION .SDK_INT == 33 ) {
808- arrayOf(samsungContentReplacementPreventer, emptyEditTextBackspaceDetector)
809- } else
810- if (Build .VERSION .SDK_INT == Build .VERSION_CODES .O || Build .VERSION .SDK_INT == Build .VERSION_CODES .O_MR1 ) {
811- // dynamicLayoutCrashPreventer needs to be first in array as these are going to be chained when processed
812- arrayOf(dynamicLayoutCrashPreventer, emptyEditTextBackspaceDetector)
813- } else {
814- arrayOf(emptyEditTextBackspaceDetector)
815- }
738+ if (Build .VERSION .SDK_INT == Build .VERSION_CODES .O || Build .VERSION .SDK_INT == Build .VERSION_CODES .O_MR1 ) {
739+ // dynamicLayoutCrashPreventer needs to be first in array as these are going to be chained when processed
740+ filters = arrayOf(dynamicLayoutCrashPreventer, emptyEditTextBackspaceDetector)
741+ } else {
742+ filters = arrayOf(emptyEditTextBackspaceDetector)
743+ }
816744 }
817745
818746 private fun isCleanStringEmpty (text : CharSequence ): Boolean {
@@ -1797,14 +1725,13 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
17971725 bypassMediaDeletedListener = false
17981726 }
17991727
1728+ // removes Grammarly suggestions from default keyboard on Samsung devices on Android 13 (API 33)
1729+ // Grammarly implementation is often messing spans and cursor position, as described here:
1730+ // https://github.com/wordpress-mobile/AztecEditor-Android/issues/1023
18001731 fun enableSamsungPredictiveBehaviorOverride () {
18011732 overrideSamsungPredictiveBehavior = true
18021733 }
18031734
1804- fun disableSamsungPredictiveBehaviorOverride () {
1805- overrideSamsungPredictiveBehavior = false
1806- }
1807-
18081735 fun isMediaDeletedListenerDisabled (): Boolean {
18091736 return bypassMediaDeletedListener
18101737 }
0 commit comments