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