Skip to content

Commit 1c02b62

Browse files
leticiarossipaulfthomas
authored andcommitted
[ExposedDropdownMenu] Update background when setInputType is called so that ripple is or isn't present properly.
PiperOrigin-RevId: 437345929
1 parent 0ba0d65 commit 1c02b62

5 files changed

Lines changed: 106 additions & 18 deletions

File tree

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

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,19 @@ boolean isBoxBackgroundModeSupported(@BoxBackgroundMode int boxBackgroundMode) {
292292
return boxBackgroundMode != TextInputLayout.BOX_BACKGROUND_NONE;
293293
}
294294

295+
/*
296+
* This method should be called if the ripple background should be updated. For example,
297+
* if a new {@link ShapeAppearanceModel} is set on the text field, or if a different
298+
* {@link InputType} is set on the {@link AutoCompleteTextView}.
299+
*/
300+
void updateBackground(@NonNull AutoCompleteTextView editText) {
301+
if (isEditable(editText)) {
302+
removeRippleEffect(editText);
303+
} else {
304+
addRippleEffect(editText);
305+
}
306+
}
307+
295308
private void showHideDropdown(@Nullable AutoCompleteTextView editText) {
296309
if (editText == null) {
297310
return;
@@ -328,18 +341,15 @@ private void setPopupBackground(@NonNull AutoCompleteTextView editText) {
328341
}
329342
}
330343

331-
/*
332-
* This method should be called if the outlined ripple background should be updated. For example,
333-
* if a new {@link ShapeAppearanceModel} is set on the text field.
334-
*/
335-
void updateOutlinedRippleEffect(@NonNull AutoCompleteTextView editText) {
336-
if (isEditable(editText)
337-
|| textInputLayout.getBoxBackgroundMode() != TextInputLayout.BOX_BACKGROUND_OUTLINE
338-
|| !(editText.getBackground() instanceof LayerDrawable)) {
344+
/* Remove ripple effect from editable layouts if it's present. */
345+
private void removeRippleEffect(@NonNull AutoCompleteTextView editText) {
346+
if (!(editText.getBackground() instanceof LayerDrawable) || !isEditable(editText)) {
339347
return;
340348
}
341-
342-
addRippleEffect(editText);
349+
int boxBackgroundMode = textInputLayout.getBoxBackgroundMode();
350+
LayerDrawable layerDrawable = (LayerDrawable) editText.getBackground();
351+
int backgroundLayerIndex = boxBackgroundMode == TextInputLayout.BOX_BACKGROUND_OUTLINE ? 1 : 0;
352+
ViewCompat.setBackground(editText, layerDrawable.getDrawable(backgroundLayerIndex));
343353
}
344354

345355
/* Add ripple effect to non editable layouts. */

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,15 @@ public <T extends ListAdapter & Filterable> void setAdapter(@Nullable T adapter)
158158
modalListPopup.setAdapter(getAdapter());
159159
}
160160

161+
@Override
162+
public void setInputType(int type) {
163+
super.setInputType(type);
164+
TextInputLayout textInputLayout = findTextInputLayoutAncestor();
165+
if (textInputLayout != null) {
166+
textInputLayout.updateDropdownMenuBackground();
167+
}
168+
}
169+
161170
/**
162171
* Sets the simple string items of auto-completion with the given string array resource. This
163172
* method will create a default {@link ArrayAdapter} with a default item layout specified by

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

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2612,7 +2612,9 @@ private void applyBoxAttributes() {
26122612
boxBackground.setShapeAppearanceModel(shapeAppearanceModel);
26132613
// The outlined background of the dropdown menu is created in the end icon delegate, so it
26142614
// needs to be updated based on the new shape appearance model.
2615-
updateDropdownMenuBackground();
2615+
if (boxBackgroundMode == BOX_BACKGROUND_OUTLINE) {
2616+
updateDropdownMenuBackground();
2617+
}
26162618
}
26172619

26182620
if (canDrawOutlineStroke()) {
@@ -2656,13 +2658,15 @@ private boolean canDrawStroke() {
26562658
}
26572659

26582660
/*
2659-
* This method should be called if the outlined ripple background should be updated. For example,
2660-
* if a new {@link ShapeAppearanceModel} is set on the text field.
2661+
* This method should be called when the {@link TextInputLayout} is acting as an exposed dropdown
2662+
* menu and its ripple background needs to be updated. For example, if a new
2663+
* {@link ShapeAppearanceModel} is set on the outlined text field, or if a different
2664+
* {@link InputType} is set on the layout's {@link AutoCompleteTextView}.
26612665
*/
2662-
private void updateDropdownMenuBackground() {
2663-
if (getEndIconMode() == END_ICON_DROPDOWN_MENU && boxBackgroundMode == BOX_BACKGROUND_OUTLINE) {
2666+
void updateDropdownMenuBackground() {
2667+
if (getEndIconMode() == END_ICON_DROPDOWN_MENU) {
26642668
((DropdownMenuEndIconDelegate) endLayout.getEndIconDelegate())
2665-
.updateOutlinedRippleEffect((AutoCompleteTextView) editText);
2669+
.updateBackground((AutoCompleteTextView) editText);
26662670
}
26672671
}
26682672

tests/javatests/com/google/android/material/testutils/TextInputLayoutActions.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import android.view.View;
2929
import android.view.View.OnClickListener;
3030
import android.view.View.OnLongClickListener;
31+
import android.widget.AutoCompleteTextView;
3132
import androidx.annotation.ColorInt;
3233
import androidx.annotation.DimenRes;
3334
import androidx.test.espresso.UiController;
@@ -870,4 +871,26 @@ public void perform(UiController uiController, View view) {
870871
}
871872
};
872873
}
874+
875+
/** Sets the input type on an AutoCompleteTextView. */
876+
public static ViewAction setInputType(final int inputType) {
877+
return new ViewAction() {
878+
879+
@Override
880+
public Matcher<View> getConstraints() {
881+
return ViewMatchers.isAssignableFrom(AutoCompleteTextView.class);
882+
}
883+
884+
@Override
885+
public String getDescription() {
886+
return "Sets input type.";
887+
}
888+
889+
@Override
890+
public void perform(UiController uiController, View view) {
891+
AutoCompleteTextView autoCompleteTextView = (AutoCompleteTextView) view;
892+
autoCompleteTextView.setInputType(inputType);
893+
}
894+
};
895+
}
873896
}

tests/javatests/com/google/android/material/textfield/ExposedDropdownMenuTest.java

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,20 @@
2828
import static androidx.test.espresso.matcher.ViewMatchers.withId;
2929
import static com.google.android.material.testutils.TestUtilsActions.waitFor;
3030
import static com.google.android.material.testutils.TextInputLayoutActions.clickIcon;
31+
import static com.google.android.material.testutils.TextInputLayoutActions.setInputType;
3132
import static com.google.android.material.testutils.TextInputLayoutActions.skipAnimations;
3233
import static com.google.android.material.testutils.TextInputLayoutMatchers.endIconHasContentDescription;
3334
import static org.hamcrest.MatcherAssert.assertThat;
3435
import static org.hamcrest.Matchers.allOf;
36+
import static org.hamcrest.Matchers.instanceOf;
37+
import static org.hamcrest.Matchers.not;
3538
import static org.hamcrest.core.Is.is;
3639
import static org.junit.Assert.assertNull;
3740

3841
import android.app.Activity;
42+
import android.graphics.drawable.Drawable;
43+
import android.graphics.drawable.LayerDrawable;
44+
import android.text.InputType;
3945
import android.widget.AutoCompleteTextView;
4046
import androidx.test.filters.MediumTest;
4147
import androidx.test.rule.ActivityTestRule;
@@ -49,12 +55,13 @@
4955
@MediumTest
5056
@RunWith(AndroidJUnit4.class)
5157
public class ExposedDropdownMenuTest {
58+
59+
private static final String INPUT_TEXT = "I";
60+
5261
@Rule
5362
public final ActivityTestRule<ExposedDropdownMenuActivity> activityTestRule =
5463
new ActivityTestRule<>(ExposedDropdownMenuActivity.class);
5564

56-
private static final String INPUT_TEXT = "I";
57-
5865
@Test
5966
public void testMenuIsNonEditableWithInputTypeNone() {
6067
final Activity activity = activityTestRule.getActivity();
@@ -63,6 +70,41 @@ public void testMenuIsNonEditableWithInputTypeNone() {
6370
assertNull(editText.getKeyListener());
6471
}
6572

73+
@Test
74+
public void testNonEditableMenu_hasLayerBackground() {
75+
Activity activity = activityTestRule.getActivity();
76+
77+
AutoCompleteTextView editText = activity.findViewById(R.id.edittext_filled);
78+
79+
assertThat(editText.getBackground(), instanceOf(LayerDrawable.class));
80+
}
81+
82+
@Test
83+
public void testEditableMenu_doesNotHaveLayerBackground() {
84+
Activity activity = activityTestRule.getActivity();
85+
86+
AutoCompleteTextView editText = activity.findViewById(R.id.edittext_filled_editable);
87+
88+
assertThat(editText.getBackground(), not(instanceOf(LayerDrawable.class)));
89+
}
90+
91+
@Test
92+
public void testSwitchingInputType_updatesBackground() {
93+
final Activity activity = activityTestRule.getActivity();
94+
AutoCompleteTextView editText = activity.findViewById(R.id.edittext_filled);
95+
96+
// Switch to an editable type.
97+
onView(withId(R.id.edittext_filled)).perform(setInputType(InputType.TYPE_CLASS_TEXT));
98+
Drawable editableTypeBackground = editText.getBackground();
99+
// Switch back to uneditable.
100+
onView(withId(R.id.edittext_filled)).perform(setInputType(InputType.TYPE_NULL));
101+
102+
// Assert background updated.
103+
assertThat(editableTypeBackground, not(instanceOf(LayerDrawable.class)));
104+
// Assert second switch updated the background back to an instance of LayerDrawable.
105+
assertThat(editText.getBackground(), instanceOf(LayerDrawable.class));
106+
}
107+
66108
@Test
67109
public void testEndIconClickShowsDropdownPopup() {
68110
final Activity activity = activityTestRule.getActivity();

0 commit comments

Comments
 (0)