Skip to content

Commit 690bbfc

Browse files
drchenleticiarossi
authored andcommitted
[TextField] Fix the issue that menu items gets filtered after recreation
It's actually a bug of framework's AutoCompleteTextView. When restoring the state, it always filters the item list regardless the previously input item is from menu selection or manual input. This change fixes the issue by implementing the custom logic of input text saving/restoring, and properly remember if the last input text filters the item list or not. Resolves #1464 PiperOrigin-RevId: 716328564
1 parent 54778a9 commit 690bbfc

File tree

1 file changed

+109
-0
lines changed

1 file changed

+109
-0
lines changed

lib/java/com/google/android/material/textfield/MaterialAutoCompleteTextView.java

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,14 @@
2929
import android.graphics.drawable.ColorDrawable;
3030
import android.graphics.drawable.Drawable;
3131
import android.graphics.drawable.RippleDrawable;
32+
import android.os.Parcel;
33+
import android.os.Parcelable;
3234
import androidx.appcompat.widget.AppCompatAutoCompleteTextView;
3335
import androidx.appcompat.widget.ListPopupWindow;
36+
import android.text.Editable;
3437
import android.text.InputType;
38+
import android.text.TextUtils;
39+
import android.text.TextWatcher;
3540
import android.util.AttributeSet;
3641
import android.view.View;
3742
import android.view.View.MeasureSpec;
@@ -83,6 +88,8 @@ public class MaterialAutoCompleteTextView extends AppCompatAutoCompleteTextView
8388
private int simpleItemSelectedColor;
8489
@Nullable private ColorStateList simpleItemSelectedRippleColor;
8590

91+
@Nullable private CharSequence selectedItem;
92+
8693
public MaterialAutoCompleteTextView(@NonNull Context context) {
8794
this(context, null);
8895
}
@@ -181,6 +188,23 @@ public void onItemClick(AdapterView<?> parent, View selectedView, int position,
181188
}
182189

183190
attributes.recycle();
191+
192+
// TODO: Remove this workaround once the framework bug (b/202873898) is fixed.
193+
addTextChangedListener(
194+
new TextWatcher() {
195+
@Override
196+
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
197+
198+
@Override
199+
public void onTextChanged(CharSequence s, int start, int before, int count) {}
200+
201+
@Override
202+
public void afterTextChanged(Editable s) {
203+
if (!TextUtils.equals(selectedItem, s)) {
204+
selectedItem = null;
205+
}
206+
}
207+
});
184208
}
185209

186210
@Override
@@ -437,6 +461,55 @@ public CharSequence getHint() {
437461
return super.getHint();
438462
}
439463

464+
@Override
465+
public boolean getFreezesText() {
466+
// Always return false to handle the input text restoration by ourselves. This is required
467+
// to avoid the auto-completion from being updated when the view is recreated.
468+
return false;
469+
}
470+
471+
@Override
472+
protected void replaceText(CharSequence text) {
473+
selectedItem = text;
474+
super.replaceText(text);
475+
}
476+
477+
@Override
478+
public void setText(CharSequence text, boolean filter) {
479+
if (!filter) {
480+
// When filter is false, the text is updated by the selection from the auto-complete list.
481+
selectedItem = text;
482+
}
483+
super.setText(text, filter);
484+
}
485+
486+
@Override
487+
@NonNull
488+
public Parcelable onSaveInstanceState() {
489+
Parcelable parcelable = super.onSaveInstanceState();
490+
if (TextUtils.isEmpty(getText()) || !super.getFreezesText()) {
491+
return parcelable;
492+
}
493+
494+
SavedState savedState = new SavedState(parcelable);
495+
// Remember if the current text is from the auto-complete selection.
496+
savedState.shouldRefreshAutoCompletion = (selectedItem == null);
497+
savedState.inputText = getText();
498+
return savedState;
499+
}
500+
501+
@Override
502+
public void onRestoreInstanceState(Parcelable state) {
503+
if (!(state instanceof SavedState)) {
504+
super.onRestoreInstanceState(state);
505+
return;
506+
}
507+
508+
SavedState savedState = (SavedState) state;
509+
setText(savedState.inputText, savedState.shouldRefreshAutoCompletion);
510+
super.onRestoreInstanceState(savedState.getSuperState());
511+
}
512+
440513
@Override
441514
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
442515
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -622,4 +695,40 @@ private boolean hasSelectedRippleColor() {
622695
return simpleItemSelectedRippleColor != null;
623696
}
624697
}
698+
699+
private static final class SavedState extends BaseSavedState {
700+
701+
private boolean shouldRefreshAutoCompletion;
702+
private CharSequence inputText;
703+
704+
public SavedState(Parcelable superState) {
705+
super(superState);
706+
}
707+
708+
public SavedState(Parcel source) {
709+
super(source);
710+
shouldRefreshAutoCompletion = source.readInt() != 0;
711+
inputText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
712+
}
713+
714+
@Override
715+
public void writeToParcel(Parcel out, int flags) {
716+
super.writeToParcel(out, flags);
717+
out.writeInt(shouldRefreshAutoCompletion ? 1 : 0);
718+
TextUtils.writeToParcel(inputText, out, flags);
719+
}
720+
721+
public static final Creator<SavedState> CREATOR =
722+
new Creator<SavedState>() {
723+
@Override
724+
public SavedState createFromParcel(Parcel source) {
725+
return new SavedState(source);
726+
}
727+
728+
@Override
729+
public SavedState[] newArray(int size) {
730+
return new SavedState[size];
731+
}
732+
};
733+
}
625734
}

0 commit comments

Comments
 (0)