Skip to content

Commit

Permalink
Merge pull request #804 from wordpress-mobile/release/1.3.24
Browse files Browse the repository at this point in the history
Merge Release/1.3.24 into master
  • Loading branch information
jtreanor authored Apr 5, 2019
2 parents 1b6e4b9 + b79d028 commit 40cde2f
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 8 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
# Changelog
## [v1.3.24](https://github.com/wordpress-mobile/AztecEditor-Android/releases/tag/v1.3.24)
### Changed
- Improvement to how clickable URL spans are handled #793

## [v1.3.23](https://github.com/wordpress-mobile/AztecEditor-Android/releases/tag/v1.3.23)
### Fixed
- Fix for crash when inserting characters right before an image #801

## [v1.3.22](https://github.com/wordpress-mobile/AztecEditor-Android/releases/tag/v1.3.22)
### Fixed
- Fix for crash on Samsung Clipboard ListView on Android 8.X #795
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ repositories {
```
```gradle
dependencies {
api ('com.github.wordpress-mobile.WordPress-Aztec-Android:aztec:v1.3.22')
api ('com.github.wordpress-mobile.WordPress-Aztec-Android:aztec:v1.3.24')
}
```

Expand Down
24 changes: 24 additions & 0 deletions aztec/src/main/kotlin/org/wordpress/aztec/Aztec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ open class Aztec private constructor(val visualEditor: AztecText, val toolbar: I
private var onAudioTappedListener: AztecText.OnAudioTappedListener? = null
private var onMediaDeletedListener: AztecText.OnMediaDeletedListener? = null
private var onVideoInfoRequestedListener: AztecText.OnVideoInfoRequestedListener? = null
private var onLinkTappedListener: AztecText.OnLinkTappedListener? = null
private var isLinkTapEnabled: Boolean = false
private var plugins: ArrayList<IAztecPlugin> = visualEditor.plugins
var sourceEditor: SourceViewEditText? = null

Expand Down Expand Up @@ -134,6 +136,18 @@ open class Aztec private constructor(val visualEditor: AztecText, val toolbar: I
return this
}

fun setOnLinkTappedListener(onLinkTappedListener: AztecText.OnLinkTappedListener): Aztec {
this.onLinkTappedListener = onLinkTappedListener
initLinkTappedListener()
return this
}

fun setLinkTapEnabled(isLinkTapEnabled: Boolean): Aztec {
this.isLinkTapEnabled = isLinkTapEnabled
initLinkTapEnabled()
return this
}

fun addPlugin(plugin: IAztecPlugin): Aztec {
plugins.add(plugin)

Expand Down Expand Up @@ -219,4 +233,14 @@ open class Aztec private constructor(val visualEditor: AztecText, val toolbar: I
visualEditor.setOnVideoInfoRequestedListener(onVideoInfoRequestedListener!!)
}
}

private fun initLinkTappedListener() {
if (onLinkTappedListener != null) {
visualEditor.setOnLinkTappedListener(onLinkTappedListener!!)
}
}

private fun initLinkTapEnabled() {
visualEditor.setLinkTapEnabled(isLinkTapEnabled)
}
}
86 changes: 83 additions & 3 deletions aztec/src/main/kotlin/org/wordpress/aztec/AztecText.kt
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,8 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
private var consumeSelectionChangedEvent: Boolean = false
private var isInlineTextHandlerEnabled: Boolean = true
private var bypassObservationQueue: Boolean = false
private var bypassMediaDeletedListener: Boolean = false
private var bypassCrashPreventerInputFilter: Boolean = false

var initialEditorContentParsedSHA256: ByteArray = ByteArray(0)

Expand Down Expand Up @@ -322,6 +324,10 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
fun onBackspaceKey() : Boolean
}

interface OnLinkTappedListener {
fun onLinkTapped(widget: View, url: String)
}

constructor(context: Context) : super(context) {
init(null)
}
Expand Down Expand Up @@ -420,7 +426,7 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
// triggers ClickableSpan onClick() events
movementMethod = EnhancedMovementMethod

setupBackspaceAndEnterDetection()
setupKeyListenersAndInputFilters()

//disable auto suggestions/correct for older devices
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
Expand All @@ -440,12 +446,52 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
// Setup the keyListener(s) for Backspace and Enter key.
// Backspace: If listener does return false we remove the style here
// Enter: Ask the listener if we need to insert or not the char
private fun setupBackspaceAndEnterDetection() {
private fun setupKeyListenersAndInputFilters() {
//hardware keyboard
setOnKeyListener { _, _, event ->
handleBackspaceAndEnter(event)
}

// This InputFilter created only for the purpose of avoiding crash described here:
// https://android-review.googlesource.com/c/platform/frameworks/base/+/634929
// https://github.com/wordpress-mobile/AztecEditor-Android/issues/729
// the rationale behind this workaround is that the specific crash happens only when adding/deleting text right
// before an AztecImageSpan, so we detect the specific case and re-create the contents only when that happens.
// This is indeed tackling the symptom rather than the actual problem, and should be removed once the real
// problem is fixed at the Android OS level as described in the following url
// https://android-review.googlesource.com/c/platform/frameworks/base/+/634929
val dynamicLayoutCrashPreventer = InputFilter { source, start, end, dest, dstart, dend ->
var temp : CharSequence? = null
if (!bypassCrashPreventerInputFilter && dstart == dend && dest.length > dend+1) {
// dstart == dend means this is an insertion
// if there are any images right after the destination position, hack the text
val spans = dest.getSpans(dstart, dend+1, AztecImageSpan::class.java)
if (spans.isNotEmpty()) {
// prevent this filter from running twice when `text.insert()` gets called a few lines below
disableCrashPreventerInputFilter()
// disable MediaDeleted listener before operating on content
disableMediaDeletedListener()

// take the source (that is, what is being inserted), and append the Image to it. We will delete
// the original Image later so to not have a duplicate.
// use Spannable to copy / keep the current spans
temp = SpannableStringBuilder(source).append(dest.subSequence(dend, dend+1))

// delete the original AztecImageSpan
text.delete(dend, dend+1)
// now insert both the new insertion _and_ the original AztecImageSpan
text.insert(dend, temp)
temp = "" // discard the original source parameter as an ouput from this InputFilter

// re-enable MediaDeleted listener
enableMediaDeletedListener()
// re-enable this very filter
enableCrashPreventerInputFilter()
}
}
temp
}

val emptyEditTextBackspaceDetector = InputFilter { source, start, end, dest, dstart, dend ->
if (selectionStart == 0 && selectionEnd == 0
&& end == 0 && start == 0
Expand All @@ -462,7 +508,12 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
source
}

filters = arrayOf(emptyEditTextBackspaceDetector)
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O || Build.VERSION.SDK_INT == Build.VERSION_CODES.O_MR1) {
// dynamicLayoutCrashPreventer needs to be first in array as these are going to be chained when processed
filters = arrayOf(dynamicLayoutCrashPreventer, emptyEditTextBackspaceDetector)
} else {
filters = arrayOf(emptyEditTextBackspaceDetector)
}
}

private fun handleBackspaceAndEnter(event: KeyEvent): Boolean {
Expand Down Expand Up @@ -786,6 +837,14 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
this.onVideoInfoRequestedListener = listener
}

fun setOnLinkTappedListener(listener: OnLinkTappedListener) {
EnhancedMovementMethod.linkTappedListener = listener
}

fun setLinkTapEnabled(isLinkTapEnabled: Boolean) {
EnhancedMovementMethod.isLinkTapEnabled = isLinkTapEnabled
}

override fun onKeyPreIme(keyCode: Int, event: KeyEvent): Boolean {
if (event.keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP) {
onImeBackListener?.onImeBack()
Expand Down Expand Up @@ -1303,6 +1362,26 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
bypassObservationQueue = false
}

fun disableCrashPreventerInputFilter() {
bypassCrashPreventerInputFilter = true
}

fun enableCrashPreventerInputFilter() {
bypassCrashPreventerInputFilter = false
}

fun disableMediaDeletedListener() {
bypassMediaDeletedListener = true
}

fun enableMediaDeletedListener() {
bypassMediaDeletedListener = false
}

fun isMediaDeletedListenerDisabled(): Boolean {
return bypassMediaDeletedListener
}

fun isTextChangedListenerDisabled(): Boolean {
return consumeEditEvent
}
Expand Down Expand Up @@ -1778,4 +1857,5 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
override fun dispatchHoverEvent(event: MotionEvent): Boolean {
return if (accessibilityDelegate.onHoverEvent(event)) true else super.dispatchHoverEvent(event)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,16 @@ import android.text.style.ClickableSpan
import android.view.MotionEvent
import android.widget.TextView
import org.wordpress.aztec.spans.AztecMediaClickableSpan
import org.wordpress.aztec.spans.AztecURLSpan
import org.wordpress.aztec.spans.UnknownClickableSpan

/**
* http://stackoverflow.com/a/23566268/569430
*/
object EnhancedMovementMethod : ArrowKeyMovementMethod() {
var isLinkTapEnabled = false
var linkTappedListener: AztecText.OnLinkTappedListener? = null

override fun onTouchEvent(widget: TextView, text: Spannable, event: MotionEvent): Boolean {
val action = event.action

Expand Down Expand Up @@ -72,11 +76,14 @@ object EnhancedMovementMethod : ArrowKeyMovementMethod() {
link = text.getSpans(off, off, ClickableSpan::class.java).firstOrNull { text.getSpanStart(it) == off }
}

if (link != null && (link is AztecMediaClickableSpan || link is UnknownClickableSpan)) {
if (action == MotionEvent.ACTION_UP) {
if (link != null) {
if (link is AztecMediaClickableSpan || link is UnknownClickableSpan) {
link.onClick(widget)
return true
} else if (link is AztecURLSpan && isLinkTapEnabled) {
linkTappedListener?.onLinkTapped(widget, link.url) ?: link.onClick(widget)
return true
}
return true
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ class DeleteMediaElementWatcherAPI25AndHigher(aztecText: AztecText) : TextWatche
return
}

if (aztecTextRef.get()?.isMediaDeletedListenerDisabled() ?: true) {
return
}

if (count > 0) {
deleted = true

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ class DeleteMediaElementWatcherPreAPI25(aztecText: AztecText) : TextWatcher {
return
}

if (aztecTextRef.get()?.isMediaDeletedListenerDisabled() ?: true) {
return
}

if (count > 0) {
aztecTextRef.get()?.text?.getSpans(start, start + count, AztecMediaSpan::class.java)
?.forEach {
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ buildscript {
picassoVersion = '2.5.2'
robolectricVersion = '3.5.1'
jUnitVersion = '4.12'
jSoupVersion = '1.10.3'
jSoupVersion = '1.11.3'
wordpressUtilsVersion = '1.21'
espressoVersion = '3.0.1'
}
Expand Down

0 comments on commit 40cde2f

Please sign in to comment.