@@ -22,13 +22,16 @@ import android.content.ClipData
2222import android.content.ClipboardManager
2323import android.content.Context
2424import android.graphics.drawable.Drawable
25+ import android.os.Build
2526import android.os.Bundle
2627import android.os.Parcel
2728import android.os.Parcelable
2829import android.support.v4.content.ContextCompat
2930import android.support.v7.app.AlertDialog
30- import android.support.v7.widget.AppCompatAutoCompleteTextView
31+ import android.support.v7.widget.AppCompatEditText
3132import android.text.Editable
33+ import android.text.InputFilter
34+ import android.text.InputType
3235import android.text.Spannable
3336import android.text.SpannableStringBuilder
3437import android.text.Spanned
@@ -41,9 +44,6 @@ import android.view.LayoutInflater
4144import android.view.View
4245import android.view.WindowManager
4346import android.view.inputmethod.BaseInputConnection
44- import android.view.inputmethod.EditorInfo
45- import android.view.inputmethod.InputConnection
46- import android.view.inputmethod.InputConnectionWrapper
4747import android.widget.EditText
4848import org.wordpress.aztec.formatting.BlockFormatter
4949import org.wordpress.aztec.formatting.InlineFormatter
@@ -84,6 +84,7 @@ import org.wordpress.aztec.watchers.InlineTextWatcher
8484import org.wordpress.aztec.watchers.ParagraphBleedAdjuster
8585import org.wordpress.aztec.watchers.ParagraphCollapseAdjuster
8686import org.wordpress.aztec.watchers.ParagraphCollapseRemover
87+ import org.wordpress.aztec.watchers.SuggestionWatcher
8788import org.wordpress.aztec.watchers.TextDeleter
8889import org.wordpress.aztec.watchers.ZeroIndexContentWatcher
8990import org.xml.sax.Attributes
@@ -92,7 +93,7 @@ import java.util.Arrays
9293import java.util.LinkedList
9394
9495@Suppress(" UNUSED_PARAMETER" )
95- class AztecText : AppCompatAutoCompleteTextView , TextWatcher , UnknownHtmlSpan .OnUnknownHtmlTappedListener {
96+ class AztecText : AppCompatEditText , TextWatcher , UnknownHtmlSpan .OnUnknownHtmlTappedListener {
9697 companion object {
9798 val BLOCK_EDITOR_HTML_KEY = " RETAINED_BLOCK_HTML_KEY"
9899 val BLOCK_EDITOR_START_INDEX_KEY = " BLOCK_EDITOR_START_INDEX_KEY"
@@ -123,6 +124,7 @@ class AztecText : AppCompatAutoCompleteTextView, TextWatcher, UnknownHtmlSpan.On
123124 private var blockEditorDialog: AlertDialog ? = null
124125 private var consumeEditEvent: Boolean = false
125126 private var consumeSelectionChangedEvent: Boolean = false
127+ private var isInlineTextHandlerEnabled: Boolean = true
126128
127129 private var onSelectionChangedListener: OnSelectionChangedListener ? = null
128130 private var onImeBackListener: OnImeBackListener ? = null
@@ -135,6 +137,8 @@ class AztecText : AppCompatAutoCompleteTextView, TextWatcher, UnknownHtmlSpan.On
135137 private var isLeadingStyleRemoved = false
136138 private var previousCursorPosition = 0
137139
140+ private var isHandlingBackspaceEvent = false
141+
138142 var isInCalypsoMode = true
139143
140144 private var unknownBlockSpanStart = - 1
@@ -287,9 +291,11 @@ class AztecText : AppCompatAutoCompleteTextView, TextWatcher, UnknownHtmlSpan.On
287291 // triggers ClickableSpan onClick() events
288292 movementMethod = EnhancedMovementMethod
289293
290- // detect the press of backspace from hardware keyboard when no characters are deleted (eg. at 0 index of EditText)
291- setOnKeyListener { _, _, event ->
292- handleBackspace(event)
294+ setupZeroIndexBackspaceDetection()
295+
296+ // disable auto suggestions/correct for older devices
297+ if (Build .VERSION .SDK_INT < Build .VERSION_CODES .LOLLIPOP ) {
298+ inputType = InputType .TYPE_TEXT_FLAG_NO_SUGGESTIONS
293299 }
294300
295301 install()
@@ -302,6 +308,29 @@ class AztecText : AppCompatAutoCompleteTextView, TextWatcher, UnknownHtmlSpan.On
302308 isViewInitialized = true
303309 }
304310
311+ // detect the press of backspace when no characters are deleted (eg. at 0 index of EditText)
312+ private fun setupZeroIndexBackspaceDetection () {
313+ // hardware keyboard
314+ setOnKeyListener { _, _, event ->
315+ handleBackspace(event)
316+ }
317+
318+ // software keyboard
319+ val emptyEditTextBackspaceDetector = InputFilter { source, start, end, dest, dstart, dend ->
320+ if (selectionStart == 0 && selectionEnd == 0
321+ && end == 0 && start == 0
322+ && dstart == 0 && dend == 0
323+ && ! isHandlingBackspaceEvent) {
324+ isHandlingBackspaceEvent = true
325+ handleBackspace(KeyEvent (KeyEvent .ACTION_DOWN , KeyEvent .KEYCODE_DEL ))
326+ isHandlingBackspaceEvent = false
327+ }
328+ source
329+ }
330+
331+ filters = arrayOf(emptyEditTextBackspaceDetector)
332+ }
333+
305334 private fun handleBackspace (event : KeyEvent ): Boolean {
306335 var wasStyleRemoved = false
307336 if (event.action == KeyEvent .ACTION_DOWN && event.keyCode == KeyEvent .KEYCODE_DEL ) {
@@ -331,6 +360,10 @@ class AztecText : AppCompatAutoCompleteTextView, TextWatcher, UnknownHtmlSpan.On
331360
332361 EndOfParagraphMarkerAdder .install(this , verticalParagraphMargin)
333362
363+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .LOLLIPOP ) {
364+ SuggestionWatcher .install(this )
365+ }
366+
334367 InlineTextWatcher .install(inlineFormatter, this )
335368
336369 // NB: text change handler should not alter text before "afterTextChanged" is called otherwise not all watchers
@@ -484,7 +517,8 @@ class AztecText : AppCompatAutoCompleteTextView, TextWatcher, UnknownHtmlSpan.On
484517 }
485518
486519 companion object {
487- @JvmField val CREATOR : Parcelable .Creator <SavedState > = object : Parcelable .Creator <SavedState > {
520+ @JvmField
521+ val CREATOR : Parcelable .Creator <SavedState > = object : Parcelable .Creator <SavedState > {
488522 override fun createFromParcel (source : Parcel ): SavedState {
489523 return SavedState (source)
490524 }
@@ -944,6 +978,18 @@ class AztecText : AppCompatAutoCompleteTextView, TextWatcher, UnknownHtmlSpan.On
944978 consumeSelectionChangedEvent = false
945979 }
946980
981+ fun disableInlineTextHandling () {
982+ isInlineTextHandlerEnabled = false
983+ }
984+
985+ fun enableInlineTextHandling () {
986+ isInlineTextHandlerEnabled = true
987+ }
988+
989+ fun isInlineTextHandlerEnabled (): Boolean {
990+ return isInlineTextHandlerEnabled
991+ }
992+
947993 fun isOnSelectionListenerDisabled (): Boolean {
948994 return consumeSelectionChangedEvent
949995 }
@@ -1023,18 +1069,18 @@ class AztecText : AppCompatAutoCompleteTextView, TextWatcher, UnknownHtmlSpan.On
10231069 // do not copy unnecessary block hierarchy, just the minimum required
10241070 var deleteNext = false
10251071 output.getSpans(0 , output.length, IAztecBlockSpan ::class .java)
1026- .sortedBy { it.nestingLevel }
1027- .reversed()
1028- .forEach {
1029- if (deleteNext) {
1030- output.removeSpan(it)
1031- } else {
1032- deleteNext = output.getSpanStart(it) == 0 && output.getSpanEnd(it) == output.length
1033- if (deleteNext && it is AztecListItemSpan ) {
1034- deleteNext = false
1072+ .sortedBy { it.nestingLevel }
1073+ .reversed()
1074+ .forEach {
1075+ if (deleteNext) {
1076+ output.removeSpan(it)
1077+ } else {
1078+ deleteNext = output.getSpanStart(it) == 0 && output.getSpanEnd(it) == output.length
1079+ if (deleteNext && it is AztecListItemSpan ) {
1080+ deleteNext = false
1081+ }
10351082 }
10361083 }
1037- }
10381084
10391085 val html = Format .removeSourceEditorFormatting(parser.toHtml(output), isInCalypsoMode)
10401086
@@ -1202,28 +1248,6 @@ class AztecText : AppCompatAutoCompleteTextView, TextWatcher, UnknownHtmlSpan.On
12021248 blockEditorDialog!! .show()
12031249 }
12041250
1205- // Custom input connection is used to detect the press of backspace when no characters are deleted
1206- // (eg. at 0 index of EditText)
1207- override fun onCreateInputConnection (outAttrs : EditorInfo ): InputConnection {
1208- return AztecInputConnection (super .onCreateInputConnection(outAttrs), true )
1209- }
1210-
1211- private inner class AztecInputConnection (target : InputConnection , mutable : Boolean ) : InputConnectionWrapper(target, mutable) {
1212-
1213- override fun sendKeyEvent (event : KeyEvent ): Boolean {
1214- handleBackspace(event)
1215- return super .sendKeyEvent(event)
1216- }
1217-
1218- override fun deleteSurroundingText (beforeLength : Int , afterLength : Int ): Boolean {
1219- // detect pressing of backspace with soft keyboard on 0 index, when no text is deleted
1220- if (beforeLength == 1 && afterLength == 0 && selectionStart == 0 && selectionEnd == 0 ) {
1221- sendKeyEvent(KeyEvent (KeyEvent .ACTION_DOWN , KeyEvent .KEYCODE_DEL ))
1222- }
1223- return super .deleteSurroundingText(beforeLength, afterLength)
1224- }
1225- }
1226-
12271251 private fun deleteInlineStyleFromTheBeginning () {
12281252 inlineFormatter.tryRemoveLeadingInlineStyle()
12291253 isLeadingStyleRemoved = true
0 commit comments