hootsuite/nachos

IndexOutOfBoundsException in NachoTextView

bashtian opened this issue · 4 comments

I'm getting following exception with version 1.1.1

Exception java.lang.IndexOutOfBoundsException: getChars (0 ... 1) ends beyond length 0

android.text.SpannableStringBuilder.checkRange (SpannableStringBuilder.java:1018)
android.text.SpannableStringBuilder.getChars (SpannableStringBuilder.java:915)
android.text.TextUtils.getChars (TextUtils.java:90)
android.text.SpannableStringBuilder.<init> (SpannableStringBuilder.java:64)
android.text.SpannableStringBuilder.subSequence (SpannableStringBuilder.java:907)
com.hootsuite.nachos.NachoTextView.handleTextChanged (NachoTextView.java:839)
com.hootsuite.nachos.NachoTextView.afterTextChanged (NachoTextView.java:826)
android.widget.TextView.sendAfterTextChanged (TextView.java:8142)
android.widget.TextView$ChangeWatcher.afterTextChanged (TextView.java:10322)
android.text.SpannableStringBuilder.sendAfterTextChanged (SpannableStringBuilder.java:972)
android.text.SpannableStringBuilder.replace (SpannableStringBuilder.java:516)
android.text.SpannableStringBuilder.replace (SpannableStringBuilder.java:454)
android.text.SpannableStringBuilder.replace (SpannableStringBuilder.java:33)
android.view.inputmethod.BaseInputConnection.replaceText (BaseInputConnection.java:685)
android.view.inputmethod.BaseInputConnection.setComposingText (BaseInputConnection.java:445)
com.android.internal.view.IInputConnectionWrapper.executeMessage (IInputConnectionWrapper.java:340)
com.android.internal.view.IInputConnectionWrapper$MyHandler.handleMessage (IInputConnectionWrapper.java:78)
android.os.Handler.dispatchMessage (Handler.java:102)
android.os.Looper.loop (Looper.java:135)
android.app.ActivityThread.main (ActivityThread.java:5930)
java.lang.reflect.Method.invoke (Method.java)
java.lang.reflect.Method.invoke (Method.java:372)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:1405)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1200)

Hey @bashtian can you give me the steps to reproduce? We've seen this problem for IndexOutOfBoundsExceptipn before for larger strings, but not empty.

I use this code:

        final NachoTextView nachoTextView = (NachoTextView) view.findViewById(R.id.nacho_text_view);
        nachoTextView.setIllegalCharacters('\"');
        nachoTextView.addChipTerminator('\n', ChipTerminatorHandler.BEHAVIOR_CHIPIFY_ALL);
        nachoTextView.addChipTerminator(' ', ChipTerminatorHandler.BEHAVIOR_CHIPIFY_TO_TERMINATOR);
        nachoTextView.addChipTerminator(';', ChipTerminatorHandler.BEHAVIOR_CHIPIFY_CURRENT_TOKEN);
        nachoTextView.setNachoValidator(new ChipifyingNachoValidator());

        final Button addButton = (Button) view.findViewById(R.id.addButton);
        addButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                nachoTextView.chipifyAllUnterminatedTokens();
            }
        });

It crashes when pressing the addButton and entering text at the same time.

I'm seeing a similar (same?) crash when just typing in the NachoTextView. It happens as early as the second chip, and seems to happen when I type fast or use the swipe feature of the keyboard.
Using version 1.1.1, Android version 5.1.1, API 22.
Callstack:

java.lang.IndexOutOfBoundsException: getChars (20 ... 24) ends beyond length 20
                      at android.text.SpannableStringBuilder.checkRange(SpannableStringBuilder.java:1018)
                      at android.text.SpannableStringBuilder.getChars(SpannableStringBuilder.java:915)
                      at android.text.TextUtils.getChars(TextUtils.java:90)
                      at android.text.SpannableStringBuilder.<init>(SpannableStringBuilder.java:64)
                      at android.text.SpannableStringBuilder.subSequence(SpannableStringBuilder.java:907)
                      at com.hootsuite.nachos.NachoTextView.handleTextChanged(NachoTextView.java:839)
                      at com.hootsuite.nachos.NachoTextView.afterTextChanged(NachoTextView.java:826)
                      at android.widget.TextView.sendAfterTextChanged(TextView.java:8160)
                      at android.widget.TextView$ChangeWatcher.afterTextChanged(TextView.java:10301)
                      at android.text.SpannableStringBuilder.sendAfterTextChanged(SpannableStringBuilder.java:972)
                      at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:516)
                      at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:454)
                      at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:33)
                      at android.view.inputmethod.BaseInputConnection.replaceText(BaseInputConnection.java:685)
                      at android.view.inputmethod.BaseInputConnection.setComposingText(BaseInputConnection.java:445)
                      at com.android.internal.view.IInputConnectionWrapper.executeMessage(IInputConnectionWrapper.java:340)
                      at com.android.internal.view.IInputConnectionWrapper$MyHandler.handleMessage(IInputConnectionWrapper.java:78)
                      at android.os.Handler.dispatchMessage(Handler.java:102)
                      at android.os.Looper.loop(Looper.java:135)
                      at android.app.ActivityThread.main(ActivityThread.java:5912)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at java.lang.reflect.Method.invoke(Method.java:372)
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1405)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1200)

The code that causes this to repro:

mInput  = v.findViewById(R.id.nachoChipsInput);
mInput.addChipTerminator('\n', ChipTerminatorHandler.BEHAVIOR_CHIPIFY_ALL);
mInput.addChipTerminator(';',ChipTerminatorHandler.BEHAVIOR_CHIPIFY_CURRENT_TOKEN);
mInput.addChipTerminator(',',ChipTerminatorHandler.BEHAVIOR_CHIPIFY_CURRENT_TOKEN);

If I don't add any ChipTerminators, the issue doesn't repro.

My gut suggests there's a race condition where getText is returning an older version of the text before the changes that triggered the event updated it.

I'm happy to help in any way I can to get to the bottom of this. This is the best Chips library around and I'm currently blocked from using it by this. Let me know if there's more information I can provide or testing I can do.

Edit: Actually, I found that by changing this line
mInput.addChipTerminator('\n', ChipTerminatorHandler.BEHAVIOR_CHIPIFY_ALL);
to this
mInput.addChipTerminator('\n', ChipTerminatorHandler.BEHAVIOR_CHIPIFY_TO_TERMINATOR);
my crashes all went away.