4
votes

I'm using the below InputFilter to filter out invalid (ASCII with decimal value above 127) and the EditText displays the text twice when an invalid character is entered. I do want the EditText to show the valid characters, below is an example of what happens.

-user enters XYZ€ in the EditText component
-toast message appears on the screen stating "Invalid non-Ascii Character"
-EditText component shows xyz on the screen which is what I expected
-user enters a valid character, A so the screen shows XYZA
-InputFilter runs and returns XYZA but XYZXYZA appears in the EditText component which is not correct. Its duplicating the XYZ

Any ideas on why its duplicating the entered text after processing an invalid character?

Screen:

<EditText android:id="@+id/editText"
    android:layout_width="fill_parent" android:layout_height="120dp"
    android:layout_marginTop="10dp" android:layout_marginLeft="10dp"
    android:layout_marginRight="10dp" android:maxLength="45"
    android:focusable="true" android:inputType="text"
    android:cursorVisible="true" android:imeOptions="actionDone"
 />

Activity:

public class EditTextActivity extends Activity {        

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        EditText eText = (EditText) findViewById(R.id.editText);
        setAsciiTextFilter();
    }    

    private void setAsciiTextFilter() {

              InputFilter filter = new InputFilter() {

                    int asciiNo;

                    @Override
                    public CharSequence filter(CharSequence source, int start, int end,
                            Spanned dest, int dstart, int dend) {

                        for (int i = start; i < end; i++) {

                            asciiNo = source.charAt(i);

                            if(asciiNo > 127) {       

                                toast = mUtility.showToast("Invalid non-Ascii Character", Toast.LENGTH_SHORT);

                                //Replace the invalid ascii character with empty String
                                return source.toString().replace(source.charAt(i)+"", "");
                            }    
                        }
                        return null;
                    }
                };


           eText.setFilters(new InputFilter[]{filter}); 
    }
}

New Attempt:

 InputFilter filter = new InputFilter() {
                        @Override
                        public CharSequence filter(CharSequence source, int start, int end,
                                Spanned dest, int dstart, int dend) {

                            if (source instanceof SpannableStringBuilder) {
                                SpannableStringBuilder sourceAsSpannableBuilder = (SpannableStringBuilder)source;
                                for (int i = end - 1; i >= start; i--) { 
                                    char currentChar = source.charAt(i);
                                    int ascii = currentChar;
                                     if (ascii > 127) {    
                                         sourceAsSpannableBuilder.delete(i, i+1);
                                         toast = mUtility.showToast("Invalid non-Ascii Character", Toast.LENGTH_SHORT);
                                     }     
                                }
                                return source;
                            } else {
                                StringBuilder filteredStringBuilder = new StringBuilder();
                                for (int i = 0; i < end; i++) { 
                                    char currentChar = source.charAt(i);
                                    int ascii = currentChar;
                                    if (ascii <= 127) {    
                                        filteredStringBuilder.append(currentChar);
                                    }     
                                }
                                return filteredStringBuilder.toString();
                            }
                        }
                    };
2

2 Answers

2
votes

I find it is better to use a single for loop and answer.

Also note that it is important to pass source to the SpannableStringBuilder constructor in order to copy the spans over from source. If you don't do this then things go wonky.

    @Override
    public CharSequence filter(CharSequence source, int start,
            int end, Spanned dest, int dstart, int dend) {
        SpannableStringBuilder ret;

        if (source instanceof SpannableStringBuilder) {
            ret = (SpannableStringBuilder)source;
        } else {
            ret = new SpannableStringBuilder(source);
        }

        for (int i = end - 1; i >= start; i--) {
            char currentChar = source.charAt(i);
            char currentChar = source.charAt(i);
            int ascii = currentChar;
            if (ascii > 127) {    
                ret.delete(i, i+1);
                toast = mUtility.showToast("Invalid non-Ascii Character", Toast.LENGTH_SHORT);
            }     
        }

        return ret;
    }
1
votes

Edited:

I believe the issue is that you're returning the whole string, when you should only be returning the replacement for that character. filter() runs whenever the text changes, and doesn't necessarily replace the whole string in the EditText. You need to watch out for that, so you don't end up shoving the whole string where a character should go.

This question is related(just substitute non-ascii for non-alphanumeric), and the answer there is well accepted, so you should be able to use that to get what you want.

Sorry about the confusing answer/delete thing. I answered right before I left the house. A few minutes later, I realized a gaping flaw in my logic, so I hopped on mobile and deleted it. I hate trying to type a full answer out on my phone, so it just had to wait a bit.