Skip to content

Commit

Permalink
[ExposedDropdownMenu] Update background when setInputType is called s…
Browse files Browse the repository at this point in the history
…o that ripple is or isn't present properly.

PiperOrigin-RevId: 437345929
  • Loading branch information
leticiarossi authored and paulfthomas committed Mar 28, 2022
1 parent 0ba0d65 commit 1c02b62
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 18 deletions.
Expand Up @@ -292,6 +292,19 @@ boolean isBoxBackgroundModeSupported(@BoxBackgroundMode int boxBackgroundMode) {
return boxBackgroundMode != TextInputLayout.BOX_BACKGROUND_NONE;
}

/*
* This method should be called if the ripple background should be updated. For example,
* if a new {@link ShapeAppearanceModel} is set on the text field, or if a different
* {@link InputType} is set on the {@link AutoCompleteTextView}.
*/
void updateBackground(@NonNull AutoCompleteTextView editText) {
if (isEditable(editText)) {
removeRippleEffect(editText);
} else {
addRippleEffect(editText);
}
}

private void showHideDropdown(@Nullable AutoCompleteTextView editText) {
if (editText == null) {
return;
Expand Down Expand Up @@ -328,18 +341,15 @@ private void setPopupBackground(@NonNull AutoCompleteTextView editText) {
}
}

/*
* This method should be called if the outlined ripple background should be updated. For example,
* if a new {@link ShapeAppearanceModel} is set on the text field.
*/
void updateOutlinedRippleEffect(@NonNull AutoCompleteTextView editText) {
if (isEditable(editText)
|| textInputLayout.getBoxBackgroundMode() != TextInputLayout.BOX_BACKGROUND_OUTLINE
|| !(editText.getBackground() instanceof LayerDrawable)) {
/* Remove ripple effect from editable layouts if it's present. */
private void removeRippleEffect(@NonNull AutoCompleteTextView editText) {
if (!(editText.getBackground() instanceof LayerDrawable) || !isEditable(editText)) {
return;
}

addRippleEffect(editText);
int boxBackgroundMode = textInputLayout.getBoxBackgroundMode();
LayerDrawable layerDrawable = (LayerDrawable) editText.getBackground();
int backgroundLayerIndex = boxBackgroundMode == TextInputLayout.BOX_BACKGROUND_OUTLINE ? 1 : 0;
ViewCompat.setBackground(editText, layerDrawable.getDrawable(backgroundLayerIndex));
}

/* Add ripple effect to non editable layouts. */
Expand Down
Expand Up @@ -158,6 +158,15 @@ public <T extends ListAdapter & Filterable> void setAdapter(@Nullable T adapter)
modalListPopup.setAdapter(getAdapter());
}

@Override
public void setInputType(int type) {
super.setInputType(type);
TextInputLayout textInputLayout = findTextInputLayoutAncestor();
if (textInputLayout != null) {
textInputLayout.updateDropdownMenuBackground();
}
}

/**
* Sets the simple string items of auto-completion with the given string array resource. This
* method will create a default {@link ArrayAdapter} with a default item layout specified by
Expand Down
Expand Up @@ -2612,7 +2612,9 @@ private void applyBoxAttributes() {
boxBackground.setShapeAppearanceModel(shapeAppearanceModel);
// The outlined background of the dropdown menu is created in the end icon delegate, so it
// needs to be updated based on the new shape appearance model.
updateDropdownMenuBackground();
if (boxBackgroundMode == BOX_BACKGROUND_OUTLINE) {
updateDropdownMenuBackground();
}
}

if (canDrawOutlineStroke()) {
Expand Down Expand Up @@ -2656,13 +2658,15 @@ private boolean canDrawStroke() {
}

/*
* This method should be called if the outlined ripple background should be updated. For example,
* if a new {@link ShapeAppearanceModel} is set on the text field.
* This method should be called when the {@link TextInputLayout} is acting as an exposed dropdown
* menu and its ripple background needs to be updated. For example, if a new
* {@link ShapeAppearanceModel} is set on the outlined text field, or if a different
* {@link InputType} is set on the layout's {@link AutoCompleteTextView}.
*/
private void updateDropdownMenuBackground() {
if (getEndIconMode() == END_ICON_DROPDOWN_MENU && boxBackgroundMode == BOX_BACKGROUND_OUTLINE) {
void updateDropdownMenuBackground() {
if (getEndIconMode() == END_ICON_DROPDOWN_MENU) {
((DropdownMenuEndIconDelegate) endLayout.getEndIconDelegate())
.updateOutlinedRippleEffect((AutoCompleteTextView) editText);
.updateBackground((AutoCompleteTextView) editText);
}
}

Expand Down
Expand Up @@ -28,6 +28,7 @@
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.widget.AutoCompleteTextView;
import androidx.annotation.ColorInt;
import androidx.annotation.DimenRes;
import androidx.test.espresso.UiController;
Expand Down Expand Up @@ -870,4 +871,26 @@ public void perform(UiController uiController, View view) {
}
};
}

/** Sets the input type on an AutoCompleteTextView. */
public static ViewAction setInputType(final int inputType) {
return new ViewAction() {

@Override
public Matcher<View> getConstraints() {
return ViewMatchers.isAssignableFrom(AutoCompleteTextView.class);
}

@Override
public String getDescription() {
return "Sets input type.";
}

@Override
public void perform(UiController uiController, View view) {
AutoCompleteTextView autoCompleteTextView = (AutoCompleteTextView) view;
autoCompleteTextView.setInputType(inputType);
}
};
}
}
Expand Up @@ -28,14 +28,20 @@
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static com.google.android.material.testutils.TestUtilsActions.waitFor;
import static com.google.android.material.testutils.TextInputLayoutActions.clickIcon;
import static com.google.android.material.testutils.TextInputLayoutActions.setInputType;
import static com.google.android.material.testutils.TextInputLayoutActions.skipAnimations;
import static com.google.android.material.testutils.TextInputLayoutMatchers.endIconHasContentDescription;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertNull;

import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.text.InputType;
import android.widget.AutoCompleteTextView;
import androidx.test.filters.MediumTest;
import androidx.test.rule.ActivityTestRule;
Expand All @@ -49,12 +55,13 @@
@MediumTest
@RunWith(AndroidJUnit4.class)
public class ExposedDropdownMenuTest {

private static final String INPUT_TEXT = "I";

@Rule
public final ActivityTestRule<ExposedDropdownMenuActivity> activityTestRule =
new ActivityTestRule<>(ExposedDropdownMenuActivity.class);

private static final String INPUT_TEXT = "I";

@Test
public void testMenuIsNonEditableWithInputTypeNone() {
final Activity activity = activityTestRule.getActivity();
Expand All @@ -63,6 +70,41 @@ public void testMenuIsNonEditableWithInputTypeNone() {
assertNull(editText.getKeyListener());
}

@Test
public void testNonEditableMenu_hasLayerBackground() {
Activity activity = activityTestRule.getActivity();

AutoCompleteTextView editText = activity.findViewById(R.id.edittext_filled);

assertThat(editText.getBackground(), instanceOf(LayerDrawable.class));
}

@Test
public void testEditableMenu_doesNotHaveLayerBackground() {
Activity activity = activityTestRule.getActivity();

AutoCompleteTextView editText = activity.findViewById(R.id.edittext_filled_editable);

assertThat(editText.getBackground(), not(instanceOf(LayerDrawable.class)));
}

@Test
public void testSwitchingInputType_updatesBackground() {
final Activity activity = activityTestRule.getActivity();
AutoCompleteTextView editText = activity.findViewById(R.id.edittext_filled);

// Switch to an editable type.
onView(withId(R.id.edittext_filled)).perform(setInputType(InputType.TYPE_CLASS_TEXT));
Drawable editableTypeBackground = editText.getBackground();
// Switch back to uneditable.
onView(withId(R.id.edittext_filled)).perform(setInputType(InputType.TYPE_NULL));

// Assert background updated.
assertThat(editableTypeBackground, not(instanceOf(LayerDrawable.class)));
// Assert second switch updated the background back to an instance of LayerDrawable.
assertThat(editText.getBackground(), instanceOf(LayerDrawable.class));
}

@Test
public void testEndIconClickShowsDropdownPopup() {
final Activity activity = activityTestRule.getActivity();
Expand Down

0 comments on commit 1c02b62

Please sign in to comment.