Merge "Fix ViewStructure.getHint() for autofill on child of TextInputLayout." into oc-support-26.0-dev
diff --git a/design/src/android/support/design/widget/TextInputLayout.java b/design/src/android/support/design/widget/TextInputLayout.java
index bd02bc3..52efdde 100644
--- a/design/src/android/support/design/widget/TextInputLayout.java
+++ b/design/src/android/support/design/widget/TextInputLayout.java
@@ -64,6 +64,7 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewStructure;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AccelerateInterpolator;
import android.widget.EditText;
@@ -121,6 +122,7 @@
private final FrameLayout mInputFrame;
EditText mEditText;
+ private CharSequence mOriginalHint;
private boolean mHintEnabled;
private CharSequence mHint;
@@ -313,6 +315,24 @@
return mTypeface;
}
+ @Override
+ public void dispatchProvideAutofillStructure(ViewStructure structure, int flags) {
+ if (mOriginalHint == null || mEditText == null) {
+ super.dispatchProvideAutofillStructure(structure, flags);
+ return;
+ }
+
+ // Temporarily sets child's hint to its original value so it is properly set in the
+ // child's ViewStructure.
+ final CharSequence hint = mEditText.getHint();
+ mEditText.setHint(mOriginalHint);
+ try {
+ super.dispatchProvideAutofillStructure(structure, flags);
+ } finally {
+ mEditText.setHint(hint);
+ }
+ }
+
private void setEditText(EditText editText) {
// If we already have an EditText, throw an exception
if (mEditText != null) {
@@ -364,7 +384,9 @@
// If we do not have a valid hint, try and retrieve it from the EditText, if enabled
if (mHintEnabled && TextUtils.isEmpty(mHint)) {
- setHint(mEditText.getHint());
+ // Save the hint so it can be restored on dispatchProvideAutofillStructure();
+ mOriginalHint = mEditText.getHint();
+ setHint(mOriginalHint);
// Clear the EditText's hint as we will display it ourselves
mEditText.setHint(null);
}
diff --git a/design/tests/src/android/support/design/testutils/ViewStructureImpl.java b/design/tests/src/android/support/design/testutils/ViewStructureImpl.java
new file mode 100644
index 0000000..c7369e9
--- /dev/null
+++ b/design/tests/src/android/support/design/testutils/ViewStructureImpl.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.design.testutils;
+
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.LocaleList;
+import android.view.ViewStructure;
+import android.view.ViewStructure.HtmlInfo.Builder;
+import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillValue;
+
+/**
+ * Simple implementation of {@link ViewStructure} that's easier to use than a Mockito mock.
+ *
+ * <p>Currently supports only {@code hint}, {@code className}, and child-related methods.
+ */
+public class ViewStructureImpl extends ViewStructure {
+
+ private CharSequence mHint;
+ private String mClassName;
+ private ViewStructureImpl[] mChildren;
+
+ @Override
+ public void setHint(CharSequence hint) {
+ mHint = hint;
+ }
+
+ // Supported methods
+ @Override
+ public CharSequence getHint() {
+ return mHint;
+ }
+
+ @Override
+ public void setChildCount(int num) {
+ mChildren = new ViewStructureImpl[num];
+ }
+
+ @Override
+ public void setClassName(String className) {
+ mClassName = className;
+ }
+
+ public String getClassName() {
+ return mClassName;
+ }
+
+ @Override
+ public int addChildCount(int num) {
+ if (mChildren == null) {
+ setChildCount(num);
+ return 0;
+ }
+ final int start = mChildren.length;
+ ViewStructureImpl[] newArray = new ViewStructureImpl[start + num];
+ System.arraycopy(mChildren, 0, newArray, 0, start);
+ mChildren = newArray;
+ return start;
+ }
+
+ @Override
+ public int getChildCount() {
+ if (mChildren == null) {
+ return 0;
+ }
+ return mChildren.length;
+ }
+
+ public ViewStructureImpl getChildAt(int index) {
+ return mChildren[index];
+ }
+
+ @Override
+ public ViewStructure newChild(int index) {
+ final ViewStructureImpl child = new ViewStructureImpl();
+ mChildren[index] = child;
+ return child;
+ }
+
+ @Override
+ public ViewStructure asyncNewChild(int index) {
+ return newChild(index);
+ }
+
+
+ // Unsupported methods
+ @Override
+ public void setId(int id, String packageName, String typeName, String entryName) {
+ }
+
+ @Override
+ public void setDimens(int left, int top, int scrollX, int scrollY, int width, int height) {
+ }
+
+ @Override
+ public void setTransformation(Matrix matrix) {
+ }
+
+ @Override
+ public void setElevation(float elevation) {
+ }
+
+ @Override
+ public void setAlpha(float alpha) {
+ }
+
+ @Override
+ public void setVisibility(int visibility) {
+ }
+
+ public void setAssistBlocked(boolean state) {
+ }
+
+ @Override
+ public void setEnabled(boolean state) {
+ }
+
+ @Override
+ public void setClickable(boolean state) {
+ }
+
+ @Override
+ public void setLongClickable(boolean state) {
+ }
+
+ @Override
+ public void setContextClickable(boolean state) {
+ }
+
+ @Override
+ public void setFocusable(boolean state) {
+ }
+
+ @Override
+ public void setFocused(boolean state) {
+ }
+
+ @Override
+ public void setAccessibilityFocused(boolean state) {
+ }
+
+ @Override
+ public void setCheckable(boolean state) {
+ }
+
+ @Override
+ public void setChecked(boolean state) {
+ }
+
+ @Override
+ public void setSelected(boolean state) {
+ }
+
+ @Override
+ public void setActivated(boolean state) {
+ }
+
+ @Override
+ public void setOpaque(boolean opaque) {
+ }
+
+ @Override
+ public void setContentDescription(CharSequence contentDescription) {
+ }
+
+ @Override
+ public void setText(CharSequence text) {
+ }
+
+ @Override
+ public void setText(CharSequence text, int selectionStart, int selectionEnd) {
+ }
+
+ @Override
+ public void setTextStyle(float size, int fgColor, int bgColor, int style) {
+ }
+
+ @Override
+ public void setTextLines(int[] charOffsets, int[] baselines) {
+ }
+
+ @Override
+ public CharSequence getText() {
+ return null;
+ }
+
+ @Override
+ public int getTextSelectionStart() {
+ return 0;
+ }
+
+ @Override
+ public int getTextSelectionEnd() {
+ return 0;
+ }
+
+ @Override
+ public Bundle getExtras() {
+ return null;
+ }
+
+ @Override
+ public boolean hasExtras() {
+ return false;
+ }
+
+ @Override
+ public AutofillId getAutofillId() {
+ return null;
+ }
+
+ @Override
+ public void setAutofillId(AutofillId id) {
+ }
+
+ public void setAutofillId(ViewStructure parent, int virtualId) {
+ }
+
+ @Override
+ public void setAutofillId(AutofillId parentId, int virtualId) {
+ }
+
+ @Override
+ public void setAutofillType(int type) {
+ }
+
+ @Override
+ public void setAutofillHints(String[] hint) {
+ }
+
+ @Override
+ public void setAutofillValue(AutofillValue value) {
+ }
+
+ @Override
+ public void setAutofillOptions(CharSequence[] options) {
+ }
+
+ @Override
+ public void setInputType(int inputType) {
+ }
+
+ @Override
+ public void setDataIsSensitive(boolean sensitive) {
+ }
+
+ @Override
+ public void asyncCommit() {
+ }
+
+ public Rect getTempRect() {
+ return null;
+ }
+
+ @Override
+ public void setWebDomain(String domain) {
+ }
+
+ @Override
+ public void setLocaleList(LocaleList localeList) {
+ }
+
+ @Override
+ public Builder newHtmlInfoBuilder(String tagName) {
+ return null;
+ }
+
+ @Override
+ public void setHtmlInfo(HtmlInfo htmlInfo) {
+ }
+}
diff --git a/design/tests/src/android/support/design/widget/TextInputLayoutTest.java b/design/tests/src/android/support/design/widget/TextInputLayoutTest.java
index 929fcd7..226463c 100755
--- a/design/tests/src/android/support/design/widget/TextInputLayoutTest.java
+++ b/design/tests/src/android/support/design/widget/TextInputLayoutTest.java
@@ -49,6 +49,7 @@
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
@@ -58,13 +59,16 @@
import android.graphics.Typeface;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.Parcelable;
import android.support.design.test.R;
import android.support.design.testutils.TestUtils;
+import android.support.design.testutils.ViewStructureImpl;
import android.support.test.annotation.UiThreadTest;
import android.support.test.espresso.NoMatchingViewException;
import android.support.test.espresso.ViewAssertion;
import android.support.test.filters.MediumTest;
+import android.support.test.filters.SdkSuppress;
import android.support.v4.widget.TextViewCompat;
import android.util.AttributeSet;
import android.util.SparseArray;
@@ -304,6 +308,30 @@
assertEquals(INPUT_TEXT, info.hintText);
}
+ @UiThreadTest
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ public void testDispatchProvideAutofillStructure() {
+ final Activity activity = mActivityTestRule.getActivity();
+
+ final TextInputLayout layout = activity.findViewById(R.id.textinput);
+
+ final ViewStructureImpl structure = new ViewStructureImpl();
+ layout.dispatchProvideAutofillStructure(structure, 0);
+
+ assertEquals(2, structure.getChildCount()); // EditText and TextView
+
+ // Asserts the structure.
+ final ViewStructureImpl childStructure = structure.getChildAt(0);
+ assertEquals(EditText.class.getName(), childStructure.getClassName());
+ assertEquals("Hint to the user", childStructure.getHint());
+
+ // Make sure the widget's hint was restored.
+ assertEquals("Hint to the user", layout.getHint());
+ final EditText editText = activity.findViewById(R.id.textinput_edittext);
+ assertNull(editText.getHint());
+ }
+
/**
* Regression test for b/31663756.
*/