2222import static com .google .android .material .timepicker .TimePickerView .GENERIC_VIEW_ACCESSIBILITY_CLASS_NAME ;
2323
2424import android .content .Context ;
25+ import android .content .res .ColorStateList ;
2526import android .content .res .Configuration ;
2627import android .os .Build .VERSION ;
2728import android .os .Build .VERSION_CODES ;
3637import android .widget .EditText ;
3738import android .widget .FrameLayout ;
3839import android .widget .TextView ;
40+ import androidx .annotation .ColorInt ;
3941import androidx .annotation .NonNull ;
4042import androidx .annotation .Nullable ;
4143import androidx .annotation .VisibleForTesting ;
4244import androidx .core .view .AccessibilityDelegateCompat ;
4345import androidx .core .view .ViewCompat ;
4446import androidx .core .view .accessibility .AccessibilityNodeInfoCompat ;
4547import com .google .android .material .chip .Chip ;
48+ import com .google .android .material .color .MaterialColors ;
4649import com .google .android .material .internal .TextWatcherAdapter ;
4750import com .google .android .material .internal .ViewUtils ;
4851import com .google .android .material .textfield .TextInputLayout ;
@@ -59,6 +62,15 @@ class ChipTextInputComboView extends FrameLayout implements Checkable {
5962 private final EditText editText ;
6063 private TextWatcher watcher ;
6164 private TextView label ;
65+ private CharSequence chipText = "" ;
66+
67+ private boolean hasError = false ;
68+ private ColorStateList originalChipBackgroundColor ;
69+ private ColorStateList originalChipTextColor ;
70+ private ColorStateList originalEditTextColor ;
71+ private ColorStateList originalEditTextCursorColor ;
72+ private ColorStateList originalLabelColor ;
73+ @ ColorInt private int originalChipStrokeColor ;
6274
6375 public ChipTextInputComboView (@ NonNull Context context ) {
6476 this (context , null );
@@ -105,10 +117,14 @@ public boolean isChecked() {
105117 @ Override
106118 public void setChecked (boolean checked ) {
107119 chip .setChecked (checked );
120+ if (checked ) {
121+ chip .setText ("" );
122+ chip .setImportantForAccessibility (View .IMPORTANT_FOR_ACCESSIBILITY_NO );
123+ } else {
124+ chip .setText (chipText );
125+ chip .setImportantForAccessibility (View .IMPORTANT_FOR_ACCESSIBILITY_YES );
126+ }
108127 editText .setVisibility (checked ? VISIBLE : INVISIBLE );
109- // TODO(b/247609386) Should not hide chip, we need the background in M3 (but not M2...).
110- // Instead, the text in chip should be hidden.
111- chip .setVisibility (checked ? GONE : VISIBLE );
112128 if (isChecked ()) {
113129 ViewUtils .requestFocusAndShowKeyboard (editText , /* useWindowInsetsController= */ false );
114130 }
@@ -121,30 +137,21 @@ public void toggle() {
121137
122138 public void setText (CharSequence text ) {
123139 String formattedText = formatText (text );
140+ chipText = formattedText ;
124141 chip .setText (formattedText );
125142 if (!isEmpty (formattedText )) {
126143 editText .removeTextChangedListener (watcher );
127144
128145 editText .setText (formattedText );
129- ViewCompat .setAccessibilityDelegate (
130- editText ,
131- new AccessibilityDelegateCompat () {
132- @ Override
133- public void onInitializeAccessibilityNodeInfo (
134- @ NonNull View host , @ NonNull AccessibilityNodeInfoCompat info ) {
135- super .onInitializeAccessibilityNodeInfo (host , info );
136- info .setText (formattedText );
137- info .setHintText (label .getText ());
138- }
139- });
146+ setAccessibilityDelegate (editText , chipText .toString (), label .getText ());
140147
141148 editText .addTextChangedListener (watcher );
142149 }
143150 }
144151
145152 @ VisibleForTesting
146153 CharSequence getChipText () {
147- return chip . getText () ;
154+ return chipText ;
148155 }
149156
150157 private String formatText (CharSequence text ) {
@@ -184,21 +191,91 @@ public void setChipDelegate(AccessibilityDelegateCompat clickActionDelegate) {
184191 ViewCompat .setAccessibilityDelegate (chip , clickActionDelegate );
185192 }
186193
194+ public void setError (boolean hasError ) {
195+ if (this .hasError == hasError ) {
196+ return ;
197+ }
198+ this .hasError = hasError ;
199+
200+ if (hasError ) {
201+ applyErrorColors ();
202+ } else {
203+ clearErrorColors ();
204+ }
205+ }
206+
207+ private void applyErrorColors () {
208+ originalChipBackgroundColor = chip .getChipBackgroundColor ();
209+ originalChipTextColor = chip .getTextColors ();
210+ originalEditTextColor = editText .getTextColors ();
211+ originalLabelColor = label .getTextColors ();
212+ originalChipStrokeColor = textInputLayout .getBoxStrokeColor ();
213+
214+ // TODO(b/394610420): tokens and ColorStateList with error state
215+ ColorStateList colorErrorContainer =
216+ MaterialColors .getColorStateListOrNull (getContext (), R .attr .colorErrorContainer );
217+ ColorStateList colorOnErrorContainer =
218+ MaterialColors .getColorStateListOrNull (getContext (), R .attr .colorOnErrorContainer );
219+ if (colorErrorContainer != null && colorOnErrorContainer != null ) {
220+ chip .setChipBackgroundColor (colorErrorContainer );
221+ chip .setTextColor (colorOnErrorContainer );
222+ editText .setTextColor (colorOnErrorContainer );
223+ textInputLayout .setBoxStrokeColor (colorOnErrorContainer .getDefaultColor ());
224+ label .setTextColor (colorOnErrorContainer );
225+ if (VERSION .SDK_INT >= VERSION_CODES .Q ) {
226+ originalEditTextCursorColor = textInputLayout .getCursorColor ();
227+ textInputLayout .setCursorColor (colorOnErrorContainer );
228+ }
229+ }
230+ }
231+
232+ private void clearErrorColors () {
233+ chip .setChipBackgroundColor (originalChipBackgroundColor );
234+ chip .setTextColor (originalChipTextColor );
235+ editText .setTextColor (originalEditTextColor );
236+ textInputLayout .setBoxStrokeColor (originalChipStrokeColor );
237+ label .setTextColor (originalLabelColor );
238+ if (VERSION .SDK_INT >= VERSION_CODES .Q ) {
239+ textInputLayout .setCursorColor (originalEditTextCursorColor );
240+ }
241+ }
242+
243+ public boolean hasError () {
244+ return hasError ;
245+ }
246+
187247 private class TextFormatter extends TextWatcherAdapter {
188248
189249 private static final String DEFAULT_TEXT = "00" ;
190250
191251 @ Override
192252 public void afterTextChanged (Editable editable ) {
193253 if (isEmpty (editable )) {
194- chip . setText ( formatText (DEFAULT_TEXT ) );
254+ chipText = formatText (DEFAULT_TEXT );
195255 return ;
196256 }
197257 String formattedText = formatText (editable );
198- chip .setText (isEmpty (formattedText ) ? formatText (DEFAULT_TEXT ) : formattedText );
258+ chipText = isEmpty (formattedText ) ? formatText (DEFAULT_TEXT ) : formattedText ;
259+ setAccessibilityDelegate (editText , editable .toString (), label .getText ());
199260 }
200261 }
201262
263+ private void setAccessibilityDelegate (
264+ @ NonNull View view , CharSequence text , @ Nullable CharSequence hint ) {
265+ ViewCompat .setAccessibilityDelegate (
266+ view ,
267+ new AccessibilityDelegateCompat () {
268+ @ Override
269+ public void onInitializeAccessibilityNodeInfo (
270+ @ NonNull View host , @ NonNull AccessibilityNodeInfoCompat info ) {
271+ super .onInitializeAccessibilityNodeInfo (host , info );
272+ info .setText (text );
273+ info .setHintText (hint );
274+ info .setMaxTextLength (2 );
275+ }
276+ });
277+ }
278+
202279 @ Override
203280 protected void onConfigurationChanged (Configuration newConfig ) {
204281 super .onConfigurationChanged (newConfig );
0 commit comments