Reputation: 9655
I have the following piece of code in my layout
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilPassword"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Password"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tilUserName"
app:passwordToggleEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/tiePassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionDone"
android:inputType="textPassword"
android:selectAllOnFocus="true"
android:singleLine="true" />
</com.google.android.material.textfield.TextInputLayout>
While navigating to TextInputLayout TalkBack announces : "password password edit box"
Desired announcement: "password edit box"
If I remove either android:hint="Password"
or android:inputType="textPassword"
it works as expected.
Notes about setting the hint
The hint should be set on TextInputLayout, rather than the TextInputEditText or EditText. If a hint is specified on the child EditText in XML, the TextInputLayout might still work correctly; TextInputLayout will use the EditText’s hint as its floating label. However, future calls to modify the hint will not update TextInputLayout’s hint. To avoid unintended behavior, call setHint() and getHint() on TextInputLayout, instead of on EditText.
Upvotes: 5
Views: 4414
Reputation: 1287
We can try giving a custom role description for the AccessibilityNode. We can check if we are showing masked password using info.isPassword property. Then build roleDescription accordingly.
class MyAccessibilityDelegate(val layout: TextInputLayout) : TextInputLayout.AccessibilityDelegate(layout) {
override fun onInitializeAccessibilityNodeInfo(host: View, info: AccessibilityNodeInfoCompat) {
super.onInitializeAccessibilityNodeInfo(host, info)
val editText = layout.editText
val content = editText?.text
info.text = content
info.roleDescription = if(!info.isPassword) "password edit text" else "edit text"
info.hintText = ""
info.isShowingHintText = false
editText?.setSelection(content?.length ?: 0)
}
}
Upvotes: 0
Reputation: 1829
By inspecting the source code of:
TextInputLayout class
one can find that:
TextInputLayout Accessibility info is provided through the following public class:
public static class AccessibilityDelegate extends AccessibilityDelegateCompat {
private final TextInputLayout layout;
public AccessibilityDelegate(TextInputLayout layout) {
this.layout = layout;
}
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
super.onInitializeAccessibilityNodeInfo(host, info);
EditText editText = layout.getEditText();
CharSequence text = (editText != null) ? editText.getText() : null;
CharSequence hintText = layout.getHint();
CharSequence errorText = layout.getError();
CharSequence counterDesc = layout.getCounterOverflowDescription();
boolean showingText = !TextUtils.isEmpty(text);
boolean hasHint = !TextUtils.isEmpty(hintText);
boolean showingError = !TextUtils.isEmpty(errorText);
boolean contentInvalid = showingError || !TextUtils.isEmpty(counterDesc);
if (showingText) {
info.setText(text);
} else if (hasHint) {
info.setText(hintText);
}
if (hasHint) {
info.setHintText(hintText);
info.setShowingHintText(!showingText && hasHint);
}
if (contentInvalid) {
info.setError(showingError ? errorText : counterDesc);
info.setContentInvalid(true);
}
}
}
and that its is applied to TextInputLayout by calling the following public method:
public void setTextInputAccessibilityDelegate(TextInputLayout.AccessibilityDelegate delegate) {
if (editText != null) {
ViewCompat.setAccessibilityDelegate(editText, delegate);
}
}
so, one can extend:
TextInputLayout.AccessibilityDelegate class and override onInitializeAccessibilityNodeInfo() to announce only what is needed. For example in your case, you can do the following:
private class CustomTextInputLayoutAccessibilityDelegate extends TextInputLayout.AccessibilityDelegate{
private final TextInputLayout layout;
public CustomTextInputLayoutAccessibilityDelegate(TextInputLayout layout) {
super(layout);
this.layout = layout;
}
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
super.onInitializeAccessibilityNodeInfo(host, info);
EditText editText = layout.getEditText();
CharSequence text = (editText != null) ? editText.getText() : null;
CharSequence hintText = layout.getHint();
CharSequence errorText = layout.getError();
//CharSequence counterDesc = layout.getCounterOverflowDescription();
boolean showingText = !TextUtils.isEmpty(text);
boolean hasHint = !TextUtils.isEmpty(hintText);
//boolean showingError = !TextUtils.isEmpty(errorText);
//boolean contentInvalid = showingError || !TextUtils.isEmpty(counterDesc);
if (showingText) {
info.setText(text);
} else if (hasHint) {
info.setText("");
}
if (hasHint) {
info.setHintText("");
info.setShowingHintText(!showingText && hasHint);
}
//if (contentInvalid) {
// info.setError(showingError ? errorText : counterDesc);
// info.setContentInvalid(true);
//}
}
}
and then call:
tilPassword.setTextInputAccessibilityDelegate(new CustomTextInputLayoutAccessibilityDelegate(tilPassword));
Upvotes: 4
Reputation: 19
It works for me. Use hint text in EditText hint.
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/_10"
android:layout_marginLeft="@dimen/_10"
android:layout_marginRight="@dimen/_10"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<EditText
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hint="Address Line 1"/>
</android.support.design.widget.TextInputLayout>
Upvotes: 0
Reputation: 885
I think it is reading your TextInputLayout hint. The layout shouldn't need a hint, move that to your TextInputEditText. You can also use the field importantForAccessability="false" on your top layout on the layout if for some reason you need a hint there.
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Password" />
</android.support.design.widget.TextInputLayout>
Upvotes: 0