From 794e1bd31b9231db5e80950c0df7c7f309c57cad Mon Sep 17 00:00:00 2001 From: khaykov Date: Wed, 11 Oct 2023 12:37:49 -0500 Subject: [PATCH 1/4] Instead of input connection override disable auto-correct. --- .../kotlin/org/wordpress/aztec/AztecText.kt | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/aztec/src/main/kotlin/org/wordpress/aztec/AztecText.kt b/aztec/src/main/kotlin/org/wordpress/aztec/AztecText.kt index 2ea53c234..8d980fdcb 100644 --- a/aztec/src/main/kotlin/org/wordpress/aztec/AztecText.kt +++ b/aztec/src/main/kotlin/org/wordpress/aztec/AztecText.kt @@ -36,6 +36,7 @@ import android.os.Parcelable import android.provider.Settings import android.text.Editable import android.text.InputFilter +import android.text.InputType import android.text.Spannable import android.text.SpannableStringBuilder import android.text.Spanned @@ -238,7 +239,6 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown private var bypassObservationQueue: Boolean = false private var bypassMediaDeletedListener: Boolean = false private var bypassCrashPreventerInputFilter: Boolean = false - private var overrideSamsungPredictiveBehavior: Boolean = false var initialEditorContentParsedSHA256: ByteArray = ByteArray(0) @@ -673,13 +673,7 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown } override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection { - val baseInputConnection = requireNotNull(super.onCreateInputConnection(outAttrs)).wrapWithBackSpaceHandler() - return if (shouldOverridePredictiveTextBehavior()) { - AppLog.d(AppLog.T.EDITOR, "Overriding predictive text behavior on Samsung device with Samsung Keyboard with API 33") - SamsungInputConnection(this, baseInputConnection) - } else { - baseInputConnection - } + return requireNotNull(super.onCreateInputConnection(outAttrs)).wrapWithBackSpaceHandler() } private fun InputConnection.wrapWithBackSpaceHandler(): InputConnection { @@ -705,7 +699,7 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown private fun shouldOverridePredictiveTextBehavior(): Boolean { val currentKeyboard = Settings.Secure.getString(context.contentResolver, Settings.Secure.DEFAULT_INPUT_METHOD) return Build.MANUFACTURER.lowercase(Locale.US) == "samsung" && Build.VERSION.SDK_INT >= 33 && - (currentKeyboard !== null && currentKeyboard.startsWith("com.samsung.android.honeyboard")) && overrideSamsungPredictiveBehavior + (currentKeyboard !== null && currentKeyboard.startsWith("com.samsung.android.honeyboard")) } // Setup the keyListener(s) for Backspace and Enter key. @@ -1778,11 +1772,13 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown bypassMediaDeletedListener = false } - // removes Grammarly suggestions from default keyboard on Samsung devices on Android 13 (API 33) + // removes auto-correct from default keyboard on Samsung devices on Android 13 (API 33) // Grammarly implementation is often messing spans and cursor position, as described here: // https://github.com/wordpress-mobile/AztecEditor-Android/issues/1023 fun enableSamsungPredictiveBehaviorOverride() { - overrideSamsungPredictiveBehavior = true + if(shouldOverridePredictiveTextBehavior()){ + inputType = inputType or InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS + } } fun isMediaDeletedListenerDisabled(): Boolean { From 03e05a7d4bd4edd6181ed22383828df2756cacf8 Mon Sep 17 00:00:00 2001 From: khaykov Date: Wed, 11 Oct 2023 12:37:58 -0500 Subject: [PATCH 2/4] Removed SamsungInputConnection.kt --- .../wordpress/aztec/SamsungInputConnection.kt | 187 ------------------ 1 file changed, 187 deletions(-) delete mode 100644 aztec/src/main/kotlin/org/wordpress/aztec/SamsungInputConnection.kt diff --git a/aztec/src/main/kotlin/org/wordpress/aztec/SamsungInputConnection.kt b/aztec/src/main/kotlin/org/wordpress/aztec/SamsungInputConnection.kt deleted file mode 100644 index 01b8f3dbd..000000000 --- a/aztec/src/main/kotlin/org/wordpress/aztec/SamsungInputConnection.kt +++ /dev/null @@ -1,187 +0,0 @@ -package org.wordpress.aztec - -import android.os.Build -import android.os.Bundle -import android.text.Editable -import android.text.Selection -import android.text.Spanned -import android.text.style.SuggestionSpan -import android.view.KeyEvent -import android.view.inputmethod.BaseInputConnection -import android.view.inputmethod.CompletionInfo -import android.view.inputmethod.CorrectionInfo -import android.view.inputmethod.ExtractedText -import android.view.inputmethod.ExtractedTextRequest -import android.view.inputmethod.InputConnection -import android.view.inputmethod.InputContentInfo - -/** - * Wrapper around proprietary Samsung InputConnection. Forwards all the calls to it, except for getExtractedText and - * some custom logic in commitText - */ -class SamsungInputConnection( - private val mTextView: AztecText, - private val baseInputConnection: InputConnection -) : BaseInputConnection(mTextView, true) { - - override fun getEditable(): Editable { - return mTextView.editableText - } - - override fun beginBatchEdit(): Boolean { - return baseInputConnection.beginBatchEdit() - } - - override fun endBatchEdit(): Boolean { - return baseInputConnection.endBatchEdit() - } - - override fun clearMetaKeyStates(states: Int): Boolean { - return baseInputConnection.clearMetaKeyStates(states) - } - - override fun sendKeyEvent(event: KeyEvent?): Boolean { - return super.sendKeyEvent(event) - } - - override fun commitCompletion(text: CompletionInfo?): Boolean { - return baseInputConnection.commitCompletion(text) - } - - override fun commitCorrection(correctionInfo: CorrectionInfo?): Boolean { - return baseInputConnection.commitCorrection(correctionInfo) - } - - override fun performEditorAction(actionCode: Int): Boolean { - return baseInputConnection.performEditorAction(actionCode) - } - - override fun performContextMenuAction(id: Int): Boolean { - return baseInputConnection.performContextMenuAction(id) - } - - // Extracted text on Samsung devices on Android 13 is somehow used for Grammarly suggestions which causes a lot of - // issues with spans and cursors. We do not use extracted text, so returning null - // (default behavior of BaseInputConnection) prevents Grammarly from messing up content most of the time - override fun getExtractedText(request: ExtractedTextRequest?, flags: Int): ExtractedText? { - return null - } - - override fun performPrivateCommand(action: String?, data: Bundle?): Boolean { - return baseInputConnection.performPrivateCommand(action, data) - } - - override fun setComposingText(text: CharSequence?, newCursorPosition: Int): Boolean { - return baseInputConnection.setComposingText(text, newCursorPosition) - } - - override fun commitText(text: CharSequence?, newCursorPosition: Int): Boolean { - val incomingTextHasSuggestions = text is Spanned && - text.getSpans(0, text.length, SuggestionSpan::class.java).isNotEmpty() - - // Sometime spellchecker tries to commit partial text with suggestions. This mostly works ok, - // but Aztec spans are finicky, and tend to get messed when content of the editor is replaced. - // In this method we do everything replaceText method of EditableInputConnection does, apart from actually - // replacing text. Instead we copy the suggestions from incoming text into editor directly. - if (incomingTextHasSuggestions) { - // delete composing text set previously. - var composingSpanStart = getComposingSpanStart(editable) - var composingSpanEnd = getComposingSpanEnd(editable) - - if (composingSpanEnd < composingSpanStart) { - val tmp = composingSpanStart - composingSpanStart = composingSpanEnd - composingSpanEnd = tmp - } - - if (composingSpanStart != -1 && composingSpanEnd != -1) { - removeComposingSpans(editable) - } else { - composingSpanStart = Selection.getSelectionStart(editable) - composingSpanEnd = Selection.getSelectionEnd(editable) - if (composingSpanStart < 0) composingSpanStart = 0 - if (composingSpanEnd < 0) composingSpanEnd = 0 - if (composingSpanEnd < composingSpanStart) { - val tmp = composingSpanStart - composingSpanStart = composingSpanEnd - composingSpanEnd = tmp - } - } - - var cursorPosition = newCursorPosition - cursorPosition += if (cursorPosition > 0) { - composingSpanEnd - 1 - } else { - composingSpanStart - } - if (newCursorPosition < 0) cursorPosition = 0 - if (newCursorPosition > editable.length) cursorPosition = editable.length - Selection.setSelection(editable, cursorPosition) - - (text as Spanned).getSpans(0, text.length, SuggestionSpan::class.java).forEach { - val st: Int = text.getSpanStart(it) - val en: Int = text.getSpanEnd(it) - val fl: Int = text.getSpanFlags(it) - - if (editable.length > composingSpanStart + en) { - editable.setSpan(it, composingSpanStart + st, composingSpanStart + en, fl) - } - } - - return true - } - return baseInputConnection.commitText(text, newCursorPosition) - } - - override fun commitContent(inputContentInfo: InputContentInfo, flags: Int, opts: Bundle?): Boolean { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { - baseInputConnection.commitContent(inputContentInfo, flags, opts) - } else { - super.commitContent(inputContentInfo, flags, opts) - } - } - - override fun deleteSurroundingText(beforeLength: Int, afterLength: Int): Boolean { - return baseInputConnection.deleteSurroundingText(beforeLength, afterLength) - } - - override fun requestCursorUpdates(cursorUpdateMode: Int): Boolean { - return baseInputConnection.requestCursorUpdates(cursorUpdateMode) - } - - override fun reportFullscreenMode(enabled: Boolean): Boolean { - return baseInputConnection.reportFullscreenMode(enabled) - } - - override fun setSelection(start: Int, end: Int): Boolean { - return baseInputConnection.setSelection(start, end) - } - - override fun finishComposingText(): Boolean { - return baseInputConnection.finishComposingText() - } - - override fun setComposingRegion(start: Int, end: Int): Boolean { - return baseInputConnection.setComposingRegion(start, end) - } - - override fun deleteSurroundingTextInCodePoints(beforeLength: Int, afterLength: Int): Boolean { - return baseInputConnection.deleteSurroundingTextInCodePoints(beforeLength, afterLength) - } - - override fun getCursorCapsMode(reqModes: Int): Int { - return baseInputConnection.getCursorCapsMode(reqModes) - } - - override fun getSelectedText(flags: Int): CharSequence? { - return baseInputConnection.getSelectedText(flags) - } - - override fun getTextAfterCursor(length: Int, flags: Int): CharSequence? { - return baseInputConnection.getTextAfterCursor(length, flags) - } - - override fun getTextBeforeCursor(length: Int, flags: Int): CharSequence? { - return baseInputConnection.getTextBeforeCursor(length, flags) - } -} From 73c889a9ab204b8ddbf4fa9bec25d32808df782e Mon Sep 17 00:00:00 2001 From: khaykov Date: Wed, 11 Oct 2023 13:28:05 -0500 Subject: [PATCH 3/4] Disabling auto-correct only when keyboard changes. --- .../main/kotlin/org/wordpress/aztec/AztecText.kt | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/aztec/src/main/kotlin/org/wordpress/aztec/AztecText.kt b/aztec/src/main/kotlin/org/wordpress/aztec/AztecText.kt index 8d980fdcb..a125de6ef 100644 --- a/aztec/src/main/kotlin/org/wordpress/aztec/AztecText.kt +++ b/aztec/src/main/kotlin/org/wordpress/aztec/AztecText.kt @@ -239,6 +239,7 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown private var bypassObservationQueue: Boolean = false private var bypassMediaDeletedListener: Boolean = false private var bypassCrashPreventerInputFilter: Boolean = false + private var overrideSamsungPredictiveBehavior: Boolean = false var initialEditorContentParsedSHA256: ByteArray = ByteArray(0) @@ -673,7 +674,14 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown } override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection { - return requireNotNull(super.onCreateInputConnection(outAttrs)).wrapWithBackSpaceHandler() + val inputConnection = requireNotNull(super.onCreateInputConnection(outAttrs)).wrapWithBackSpaceHandler() + + if (shouldOverridePredictiveTextBehavior()) { + AppLog.d(AppLog.T.EDITOR, "Disabling autocorrect on Samsung device with Samsung Keyboard with API 33") + outAttrs.inputType = outAttrs.inputType or InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS + } + + return inputConnection } private fun InputConnection.wrapWithBackSpaceHandler(): InputConnection { @@ -699,7 +707,7 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown private fun shouldOverridePredictiveTextBehavior(): Boolean { val currentKeyboard = Settings.Secure.getString(context.contentResolver, Settings.Secure.DEFAULT_INPUT_METHOD) return Build.MANUFACTURER.lowercase(Locale.US) == "samsung" && Build.VERSION.SDK_INT >= 33 && - (currentKeyboard !== null && currentKeyboard.startsWith("com.samsung.android.honeyboard")) + (currentKeyboard !== null && currentKeyboard.startsWith("com.samsung.android.honeyboard")) && overrideSamsungPredictiveBehavior } // Setup the keyListener(s) for Backspace and Enter key. @@ -1776,9 +1784,7 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown // Grammarly implementation is often messing spans and cursor position, as described here: // https://github.com/wordpress-mobile/AztecEditor-Android/issues/1023 fun enableSamsungPredictiveBehaviorOverride() { - if(shouldOverridePredictiveTextBehavior()){ - inputType = inputType or InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS - } + overrideSamsungPredictiveBehavior = true } fun isMediaDeletedListenerDisabled(): Boolean { From ed660fac552d0857179f7f66eb24d2450ebe1674 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Tue, 24 Oct 2023 17:15:55 +0300 Subject: [PATCH 4/4] Deps: Add wordpress lint dependency (2.0.0) to aztec module Release Notes: https://github.com/wordpress-mobile/ WordPress-Lint-Android/releases/tag/2.0.0 Since the 'aztec' module is still using Java files in it, it makes sense to utilize the 'org.wordpress:lint' library on it. All other modules are all Kotlin, with no Java files in it. As such, there is no point in utilizing the 'org.wordpress:lint' library on any other module. FYI: As of version '2.0.0' has only one rule, which informs about missing null annotation on Java classes. --- aztec/build.gradle | 2 ++ build.gradle | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/aztec/build.gradle b/aztec/build.gradle index fbacac837..ae7c97f3a 100644 --- a/aztec/build.gradle +++ b/aztec/build.gradle @@ -72,6 +72,8 @@ dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinCoroutinesVersion" implementation 'org.apache.commons:commons-lang3:3.8.1' + + lintChecks "org.wordpress:lint:$wordpressLintVersion" } project.afterEvaluate { diff --git a/build.gradle b/build.gradle index 34616bff1..48736488a 100644 --- a/build.gradle +++ b/build.gradle @@ -69,6 +69,7 @@ ext { } ext { + // mixed gradlePluginVersion = '3.3.1' kotlinCoroutinesVersion = '1.6.4' tagSoupVersion = '1.2.1' @@ -80,5 +81,9 @@ ext { wordpressUtilsVersion = '3.5.0' espressoVersion = '3.0.1' + // other + wordpressLintVersion = '2.0.0' + + // project aztecProjectDependency = project.hasProperty("aztecVersion") ? "org.wordpress:aztec:${project.getProperty("aztecVersion")}" : project(":aztec") }