44import android .content .res .TypedArray ;
55import android .os .Bundle ;
66import android .os .Parcelable ;
7- import android .support .v4 .text .TextUtilsCompat ;
8- import android .support .v7 .widget .AppCompatEditText ;
97import android .text .Editable ;
108import android .text .SpannableStringBuilder ;
119import android .text .TextWatcher ;
1614import android .view .View ;
1715import android .widget .TextView ;
1816
17+ import androidx .appcompat .widget .AppCompatEditText ;
18+
19+ import io .reactivex .rxjava3 .processors .BehaviorProcessor ;
20+ import kotlinx .coroutines .flow .Flow ;
21+ import kotlinx .coroutines .reactive .ReactiveFlowKt ;
22+
1923import static android .content .ContentValues .TAG ;
2024
2125public class MaskedEditText extends AppCompatEditText implements TextWatcher {
@@ -49,10 +53,11 @@ public boolean onEditorAction(TextView v, int actionId,KeyEvent event) {
4953 private int lastValidMaskPosition ;
5054 private boolean selectionChanged ;
5155 private OnFocusChangeListener focusChangeListener ;
52- private String allowedChars ;
53- private String deniedChars ;
54- private boolean shouldKeepText ;
55-
56+ private String allowedChars ;
57+ private String deniedChars ;
58+ private BehaviorProcessor <String > rawTextState = BehaviorProcessor .create ();
59+ private boolean blockFurtherSelectionChanges = false ;
60+
5661 public MaskedEditText (Context context ) {
5762 super (context );
5863 init ();
@@ -102,6 +107,11 @@ public Parcelable onSaveInstanceState() {
102107
103108 @ Override
104109 public void onRestoreInstanceState (Parcelable state ) {
110+ if (!(state instanceof Bundle )) {
111+ super .onRestoreInstanceState (state );
112+ return ;
113+ }
114+
105115 Bundle bundle = (Bundle ) state ;
106116 keepHint = bundle .getBoolean ("keepHint" , false );
107117 super .onRestoreInstanceState (((Bundle ) state ).getParcelable ("super" ));
@@ -299,7 +309,15 @@ public void onTextChanged(CharSequence s, int start, int before, int count) {
299309 if (count > 0 ) {
300310 int startingPosition = maskToRaw [nextValidPosition (start )];
301311 String addedString = s .subSequence (start , start + count ).toString ();
302- count = rawText .addToString (clear (addedString ), startingPosition , maxRawLength );
312+ try {
313+ count = rawText .addToString (clear (addedString ), startingPosition , maxRawLength );
314+ } catch (IllegalArgumentException e ) {
315+ // when exception is caught, reset view
316+ cleanUp ();
317+ setText ("" );
318+ return ;
319+ }
320+
303321 if (initialized ) {
304322 int currentPosition ;
305323 if (startingPosition + count < rawToMask .length )
@@ -329,6 +347,7 @@ public void afterTextChanged(Editable s) {
329347 editingOnChanged = false ;
330348 editingAfter = false ;
331349 ignore = false ;
350+ notifyRawTextChanged (rawText .getText ());
332351 }
333352 }
334353
@@ -346,7 +365,7 @@ protected void onSelectionChanged(int selStart, int selEnd) {
346365 // On Android 4+ this method is being called more than 1 time if there is a hint in the EditText, what moves the cursor to left
347366 // Using the boolean var selectionChanged to limit to one execution
348367
349- if (initialized ){
368+ if (initialized ){
350369 if (!selectionChanged ) {
351370 selStart = fixSelection (selStart );
352371 selEnd = fixSelection (selEnd );
@@ -361,8 +380,11 @@ protected void onSelectionChanged(int selStart, int selEnd) {
361380
362381 setSelection (selStart , selEnd );
363382 selectionChanged = true ;
364- } else {
365- //check to see if the current selection is outside the already entered text
383+ blockFurtherSelectionChanges = true ;
384+ } else if (blockFurtherSelectionChanges ) {
385+ blockFurtherSelectionChanges = false ;
386+ } else {
387+ //check to see if the current selection is outside the already entered text
366388 if (selStart > rawText .length () - 1 ){
367389 final int start = fixSelection (selStart );
368390 final int end = fixSelection (selEnd );
@@ -465,10 +487,7 @@ private Range calculateRange(int start, int end) {
465487 range .setEnd (rawText .length ());
466488 }
467489 if (range .getStart () == range .getEnd () && start < end ) {
468- int newStart = previousValidPosition (range .getStart () - 1 );
469- if (newStart < range .getStart ()) {
470- range .setStart (newStart );
471- }
490+ range .setEnd (range .getEnd () + 1 );
472491 }
473492 return range ;
474493 }
@@ -494,4 +513,12 @@ private String clear(String string) {
494513
495514 return string ;
496515 }
516+
517+ private void notifyRawTextChanged (String text ) {
518+ rawTextState .onNext (text == null ? "" : text );
519+ }
520+
521+ public Flow <String > observeRawTextChanges () {
522+ return ReactiveFlowKt .asFlow (rawTextState );
523+ }
497524}
0 commit comments