• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.widget.cts;
18 
19 import static android.widget.ListPopupWindow.INPUT_METHOD_FROM_FOCUSABLE;
20 import static android.widget.ListPopupWindow.INPUT_METHOD_NEEDED;
21 import static android.widget.ListPopupWindow.INPUT_METHOD_NOT_NEEDED;
22 
23 import static com.android.compatibility.common.util.WidgetTestUtils.sameCharSequence;
24 
25 import static com.google.common.truth.Truth.assertThat;
26 
27 import static org.junit.Assert.assertEquals;
28 import static org.junit.Assert.assertFalse;
29 import static org.junit.Assert.assertNotNull;
30 import static org.junit.Assert.assertNotSame;
31 import static org.junit.Assert.assertNull;
32 import static org.junit.Assert.assertSame;
33 import static org.junit.Assert.assertTrue;
34 import static org.mockito.Mockito.any;
35 import static org.mockito.Mockito.anyInt;
36 import static org.mockito.Mockito.atLeastOnce;
37 import static org.mockito.Mockito.eq;
38 import static org.mockito.Mockito.mock;
39 import static org.mockito.Mockito.never;
40 import static org.mockito.Mockito.spy;
41 import static org.mockito.Mockito.times;
42 import static org.mockito.Mockito.verify;
43 import static org.mockito.Mockito.verifyNoMoreInteractions;
44 import static org.mockito.Mockito.verifyZeroInteractions;
45 
46 import android.app.Activity;
47 import android.app.Instrumentation;
48 import android.app.UiModeManager;
49 import android.content.Context;
50 import android.content.res.Configuration;
51 import android.content.res.Resources;
52 import android.graphics.Color;
53 import android.graphics.Rect;
54 import android.graphics.drawable.Drawable;
55 import android.os.SystemClock;
56 import android.text.Editable;
57 import android.text.TextWatcher;
58 import android.util.AttributeSet;
59 import android.util.Xml;
60 import android.view.KeyCharacterMap;
61 import android.view.KeyEvent;
62 import android.view.View;
63 import android.view.ViewGroup;
64 import android.widget.AdapterView;
65 import android.widget.ArrayAdapter;
66 import android.widget.AutoCompleteTextView;
67 import android.widget.AutoCompleteTextView.Validator;
68 import android.widget.Filter;
69 import android.widget.Filterable;
70 import android.widget.cts.util.TestUtils;
71 
72 import androidx.test.InstrumentationRegistry;
73 import androidx.test.annotation.UiThreadTest;
74 import androidx.test.filters.MediumTest;
75 import androidx.test.rule.ActivityTestRule;
76 import androidx.test.runner.AndroidJUnit4;
77 
78 import com.android.compatibility.common.util.PollingCheck;
79 import com.android.compatibility.common.util.WidgetTestUtils;
80 import com.android.compatibility.common.util.WindowUtil;
81 
82 import com.google.common.collect.ImmutableList;
83 
84 import org.junit.Before;
85 import org.junit.Rule;
86 import org.junit.Test;
87 import org.junit.runner.RunWith;
88 import org.xmlpull.v1.XmlPullParser;
89 
90 import java.util.ArrayList;
91 import java.util.List;
92 
93 @MediumTest
94 @RunWith(AndroidJUnit4.class)
95 public class AutoCompleteTextViewTest {
96     private final static String[] WORDS =
97             new String[] { "testOne", "testTwo", "testThree", "testFour" };
98     private final static String STRING_TEST = "To be tested";
99     private final static String STRING_VALIDATED = "String Validated";
100     private final static String STRING_CHECK = "To be checked";
101 
102     private Activity mActivity;
103     private Instrumentation mInstrumentation;
104     private AutoCompleteTextView mAutoCompleteTextView;
105     private MockAutoCompleteTextView mMockAutoCompleteTextView;
106     private boolean mNumeric = false;
107     private ArrayAdapter<String> mAdapter;
108 
109     @Rule
110     public ActivityTestRule<AutoCompleteCtsActivity> mActivityRule =
111             new ActivityTestRule<>(AutoCompleteCtsActivity.class);
112 
113     private final Validator mValidator = new Validator() {
114         public CharSequence fixText(CharSequence invalidText) {
115             return STRING_VALIDATED;
116         }
117 
118         public boolean isValid(CharSequence text) {
119             return false;
120         }
121     };
122 
123     protected class MyTextWatcher implements TextWatcher {
124         private CharSequence mExpectedAfter;
125 
MyTextWatcher(CharSequence expectedAfter)126         public MyTextWatcher(CharSequence expectedAfter) {
127             mExpectedAfter = expectedAfter;
128         }
129 
130         @Override
onTextChanged(CharSequence s, int start, int before, int count)131         public void onTextChanged(CharSequence s, int start, int before, int count) {
132             assertEquals(mExpectedAfter.toString(), s.toString());
133             // This watcher is expected to be notified in the middle of completion
134             assertTrue(mAutoCompleteTextView.isPerformingCompletion());
135         }
136 
137         @Override
beforeTextChanged(CharSequence s, int start, int count, int after)138         public void beforeTextChanged(CharSequence s, int start, int count, int after) {
139         }
140 
141         @Override
afterTextChanged(Editable s)142         public void afterTextChanged(Editable s) {
143         }
144     }
145 
146     @Before
setup()147     public void setup() {
148         mActivity = mActivityRule.getActivity();
149         WindowUtil.waitForFocus(mActivity);
150         mInstrumentation = InstrumentationRegistry.getInstrumentation();
151         mAutoCompleteTextView = mActivity.findViewById(R.id.autocompletetv_edit);
152         mAutoCompleteTextView.setFocusableInTouchMode(true);
153         mMockAutoCompleteTextView = mActivity.findViewById(R.id.autocompletetv_custom);
154         mAdapter = new ArrayAdapter<>(mActivity,
155                 android.R.layout.simple_dropdown_item_1line, WORDS);
156         KeyCharacterMap keymap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
157         if (keymap.getKeyboardType() == KeyCharacterMap.NUMERIC) {
158             mNumeric = true;
159         }
160     }
161 
isTvMode()162     boolean isTvMode() {
163         UiModeManager uiModeManager = (UiModeManager) mActivity.getSystemService(
164                 Context.UI_MODE_SERVICE);
165         return uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION;
166     }
167 
168     @Test
testConstructor()169     public void testConstructor() {
170         XmlPullParser parser;
171 
172         new AutoCompleteTextView(mActivity);
173         new AutoCompleteTextView(mActivity, null);
174         new AutoCompleteTextView(mActivity, null, android.R.attr.autoCompleteTextViewStyle);
175         new AutoCompleteTextView(mActivity, null, 0,
176                 android.R.style.Widget_DeviceDefault_AutoCompleteTextView);
177         new AutoCompleteTextView(mActivity, null, 0,
178                 android.R.style.Widget_DeviceDefault_Light_AutoCompleteTextView);
179         new AutoCompleteTextView(mActivity, null, 0,
180                 android.R.style.Widget_Material_AutoCompleteTextView);
181         new AutoCompleteTextView(mActivity, null, 0,
182                 android.R.style.Widget_Material_Light_AutoCompleteTextView);
183 
184         final Resources.Theme popupTheme = mActivity.getResources().newTheme();
185         popupTheme.applyStyle(android.R.style.Theme_Material, true);
186         new AutoCompleteTextView(mActivity, null, 0,
187                 android.R.style.Widget_Material_Light_AutoCompleteTextView, popupTheme);
188 
189         // new the AutoCompleteTextView instance
190         parser = mActivity.getResources().getXml(R.layout.simple_dropdown_item_1line);
191         AttributeSet attributeSet = Xml.asAttributeSet(parser);
192         new AutoCompleteTextView(mActivity, attributeSet);
193 
194         // new the AutoCompleteTextView instance
195         parser = mActivity.getResources().getXml(R.layout.framelayout_layout);
196         attributeSet = Xml.asAttributeSet(parser);
197         new AutoCompleteTextView(mActivity, attributeSet, 0);
198 
199         // Test for negative style resource ID
200         new AutoCompleteTextView(mActivity, attributeSet, -1);
201         // Test null AttributeSet
202         new AutoCompleteTextView(mActivity, null, -1);
203     }
204 
205     @Test(expected=NullPointerException.class)
testConstructorWithNullContext()206     public void testConstructorWithNullContext() {
207         XmlPullParser parser = mActivity.getResources().getXml(R.layout.simple_dropdown_item_1line);
208         AttributeSet attributeSet = Xml.asAttributeSet(parser);
209         new AutoCompleteTextView(null, attributeSet, 0);
210     }
211 
212     @Test
testEnoughToFilter()213     public void testEnoughToFilter() throws Throwable {
214         mAutoCompleteTextView.setThreshold(3);
215         assertEquals(3, mAutoCompleteTextView.getThreshold());
216 
217         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView,
218                 () -> mAutoCompleteTextView.setText("TryToTest"));
219         assertTrue(mAutoCompleteTextView.enoughToFilter());
220 
221         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView,
222                 () -> mAutoCompleteTextView.setText("No"));
223         assertFalse(mAutoCompleteTextView.enoughToFilter());
224     }
225 
226     @UiThreadTest
227     @Test
testAccessAdapter()228     public void testAccessAdapter() {
229         mAutoCompleteTextView.setAdapter(null);
230         assertNull(mAutoCompleteTextView.getAdapter());
231 
232         mAutoCompleteTextView.setAdapter(mAdapter);
233         assertSame(mAdapter, mAutoCompleteTextView.getAdapter());
234 
235         // Re-set adapter to null
236         mAutoCompleteTextView.setAdapter(null);
237         assertNull(mAutoCompleteTextView.getAdapter());
238     }
239 
240     @UiThreadTest
241     @Test
testAccessFilter()242     public void testAccessFilter() {
243         MockAutoCompleteTextView autoCompleteTextView = new MockAutoCompleteTextView(mActivity);
244 
245         // Set Threshold to 4 characters
246         autoCompleteTextView.setThreshold(4);
247 
248         autoCompleteTextView.setAdapter(null);
249         assertNull(autoCompleteTextView.getAdapter());
250         assertNull(autoCompleteTextView.getFilter());
251 
252         Filter filter = mAdapter.getFilter();
253         assertNotNull(filter);
254         autoCompleteTextView.setAdapter(mAdapter);
255         assertSame(mAdapter, autoCompleteTextView.getAdapter());
256         assertSame(filter, autoCompleteTextView.getFilter());
257 
258         // Re-set adapter to null
259         autoCompleteTextView.setAdapter(null);
260         assertNull(autoCompleteTextView.getAdapter());
261         assertNull(autoCompleteTextView.getFilter());
262     }
263 
264     @UiThreadTest
265     @Test
testAccessItemClickListener()266     public void testAccessItemClickListener() {
267         final AdapterView.OnItemClickListener mockItemClickListener =
268                 mock(AdapterView.OnItemClickListener.class);
269 
270         // To ensure null listener
271         mAutoCompleteTextView.setOnItemClickListener(null);
272         assertNull(mAutoCompleteTextView.getItemClickListener());
273         assertNull(mAutoCompleteTextView.getOnItemClickListener());
274 
275         mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
276         assertSame(mockItemClickListener, mAutoCompleteTextView.getItemClickListener());
277         assertSame(mockItemClickListener, mAutoCompleteTextView.getOnItemClickListener());
278         verifyZeroInteractions(mockItemClickListener);
279 
280         // re-clear listener by setOnItemClickListener
281         mAutoCompleteTextView.setOnItemClickListener(null);
282         assertNull(mAutoCompleteTextView.getItemClickListener());
283         assertNull(mAutoCompleteTextView.getOnItemClickListener());
284         verifyZeroInteractions(mockItemClickListener);
285     }
286 
287     @UiThreadTest
288     @Test
testAccessItemSelectedListener()289     public void testAccessItemSelectedListener() {
290         final AdapterView.OnItemSelectedListener mockItemSelectedListener =
291                 mock(AdapterView.OnItemSelectedListener.class);
292 
293         // To ensure null listener
294         mAutoCompleteTextView.setOnItemSelectedListener(null);
295         assertNull(mAutoCompleteTextView.getItemSelectedListener());
296         assertNull(mAutoCompleteTextView.getOnItemSelectedListener());
297 
298         mAutoCompleteTextView.setOnItemSelectedListener(mockItemSelectedListener);
299         assertSame(mockItemSelectedListener, mAutoCompleteTextView.getItemSelectedListener());
300         assertSame(mockItemSelectedListener, mAutoCompleteTextView.getOnItemSelectedListener());
301         verifyZeroInteractions(mockItemSelectedListener);
302 
303         //re-clear listener by setOnItemClickListener
304         mAutoCompleteTextView.setOnItemSelectedListener(null);
305         assertNull(mAutoCompleteTextView.getItemSelectedListener());
306         assertNull(mAutoCompleteTextView.getOnItemSelectedListener());
307         verifyZeroInteractions(mockItemSelectedListener);
308     }
309 
310     @UiThreadTest
311     @Test
testConvertSelectionToString()312     public void testConvertSelectionToString() {
313         MockAutoCompleteTextView autoCompleteTextView = new MockAutoCompleteTextView(mActivity);
314 
315         // Set Threshold to 4 characters
316         autoCompleteTextView.setThreshold(4);
317         autoCompleteTextView.setAdapter(mAdapter);
318         assertNotNull(autoCompleteTextView.getAdapter());
319 
320         assertEquals("", autoCompleteTextView.convertSelectionToString(null));
321         assertEquals(STRING_TEST, autoCompleteTextView.convertSelectionToString(STRING_TEST));
322     }
323 
324     @UiThreadTest
325     @Test
testOnTextChanged()326     public void testOnTextChanged() {
327         final TextWatcher mockTextWatcher = mock(TextWatcher.class);
328         mAutoCompleteTextView.addTextChangedListener(mockTextWatcher);
329         verify(mockTextWatcher, never()).onTextChanged(any(CharSequence.class),
330                 anyInt(), anyInt(), anyInt());
331 
332         mAutoCompleteTextView.setText(STRING_TEST);
333         verify(mockTextWatcher, times(1)).onTextChanged(sameCharSequence(STRING_TEST),
334                 eq(0), eq(0), eq(STRING_TEST.length()));
335 
336         // Test replacing text.
337         mAutoCompleteTextView.setText(STRING_CHECK);
338         verify(mockTextWatcher, times(1)).onTextChanged(sameCharSequence(STRING_CHECK),
339                 eq(0), eq(STRING_TEST.length()), eq(STRING_CHECK.length()));
340     }
341 
342     @UiThreadTest
343     @Test
testPopupWindow()344     public void testPopupWindow() {
345         final AutoCompleteTextView.OnDismissListener mockDismissListener =
346                 mock(AutoCompleteTextView.OnDismissListener.class);
347         mAutoCompleteTextView.setOnDismissListener(mockDismissListener);
348 
349         assertFalse(mAutoCompleteTextView.isPopupShowing());
350         mAutoCompleteTextView.showDropDown();
351         assertTrue(mAutoCompleteTextView.isPopupShowing());
352         verifyZeroInteractions(mockDismissListener);
353 
354         mAutoCompleteTextView.dismissDropDown();
355         assertFalse(mAutoCompleteTextView.isPopupShowing());
356         verify(mockDismissListener, times(1)).onDismiss();
357 
358         mAutoCompleteTextView.showDropDown();
359         assertTrue(mAutoCompleteTextView.isPopupShowing());
360         verify(mockDismissListener, times(1)).onDismiss();
361 
362         final MockValidator validator = new MockValidator();
363         mAutoCompleteTextView.setValidator(validator);
364         mAutoCompleteTextView.requestFocus();
365         mAutoCompleteTextView.showDropDown();
366         mAutoCompleteTextView.setText(STRING_TEST);
367         assertEquals(STRING_TEST, mAutoCompleteTextView.getText().toString());
368 
369         // clearFocus will trigger onFocusChanged, and onFocusChanged will validate the text.
370         mAutoCompleteTextView.clearFocus();
371         assertFalse(mAutoCompleteTextView.isPopupShowing());
372         assertEquals(STRING_VALIDATED, mAutoCompleteTextView.getText().toString());
373         verify(mockDismissListener, times(2)).onDismiss();
374 
375         verifyNoMoreInteractions(mockDismissListener);
376     }
377 
378     @UiThreadTest
379     @Test
testDropDownMetrics()380     public void testDropDownMetrics() {
381         mAutoCompleteTextView.setAdapter(mAdapter);
382 
383         final Resources res = mActivity.getResources();
384         final int dropDownWidth =
385                 res.getDimensionPixelSize(R.dimen.autocomplete_textview_dropdown_width);
386         final int dropDownHeight =
387                 res.getDimensionPixelSize(R.dimen.autocomplete_textview_dropdown_height);
388         final int dropDownOffsetHorizontal =
389                 res.getDimensionPixelSize(R.dimen.autocomplete_textview_dropdown_offset_h);
390         final int dropDownOffsetVertical =
391                 res.getDimensionPixelSize(R.dimen.autocomplete_textview_dropdown_offset_v);
392 
393         mAutoCompleteTextView.setDropDownWidth(dropDownWidth);
394         mAutoCompleteTextView.setDropDownHeight(dropDownHeight);
395         mAutoCompleteTextView.setDropDownHorizontalOffset(dropDownOffsetHorizontal);
396         mAutoCompleteTextView.setDropDownVerticalOffset(dropDownOffsetVertical);
397 
398         mAutoCompleteTextView.showDropDown();
399 
400         assertEquals(dropDownWidth, mAutoCompleteTextView.getDropDownWidth());
401         assertEquals(dropDownHeight, mAutoCompleteTextView.getDropDownHeight());
402         assertEquals(dropDownOffsetHorizontal, mAutoCompleteTextView.getDropDownHorizontalOffset());
403         assertEquals(dropDownOffsetVertical, mAutoCompleteTextView.getDropDownVerticalOffset());
404     }
405 
406     @Test
testDropDownBackground()407     public void testDropDownBackground() throws Throwable {
408         mActivityRule.runOnUiThread(() -> mAutoCompleteTextView.setAdapter(mAdapter));
409 
410         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
411             mAutoCompleteTextView.setDropDownBackgroundResource(R.drawable.blue_fill);
412             mAutoCompleteTextView.showDropDown();
413         });
414 
415         Drawable dropDownBackground = mAutoCompleteTextView.getDropDownBackground();
416         TestUtils.assertAllPixelsOfColor("Drop down should be blue", dropDownBackground,
417                 dropDownBackground.getBounds().width(), dropDownBackground.getBounds().height(),
418                 false, Color.BLUE, 1, true);
419 
420         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
421             mAutoCompleteTextView.dismissDropDown();
422             mAutoCompleteTextView.setDropDownBackgroundDrawable(
423                     mActivity.getDrawable(R.drawable.yellow_fill));
424             mAutoCompleteTextView.showDropDown();
425         });
426 
427         dropDownBackground = mAutoCompleteTextView.getDropDownBackground();
428         TestUtils.assertAllPixelsOfColor("Drop down should be yellow", dropDownBackground,
429                 dropDownBackground.getBounds().width(), dropDownBackground.getBounds().height(),
430                 false, Color.YELLOW, 1, true);
431     }
432 
433     @Test
refreshAutoCompleteResults_addItem()434     public void refreshAutoCompleteResults_addItem() throws Throwable {
435         List<String> suggestions = new ArrayList<>(ImmutableList.of("testOne", "testTwo"));
436         mAdapter = new ArrayAdapter<String>(
437                 mActivity, android.R.layout.simple_dropdown_item_1line, suggestions);
438 
439         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
440             mAutoCompleteTextView.setAdapter(mAdapter);
441             mAutoCompleteTextView.setText("testT");
442             mAutoCompleteTextView.refreshAutoCompleteResults();
443         });
444 
445         PollingCheck.waitFor(() -> {
446             List<Object> autoCompleteSuggestions = getAutoCompleteSuggestions();
447             return (autoCompleteSuggestions.size() == 1)
448                     && autoCompleteSuggestions.contains("testTwo");
449         });
450 
451         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
452             mAdapter.add("testThree");
453             mAutoCompleteTextView.refreshAutoCompleteResults();
454         });
455 
456         PollingCheck.waitFor(() -> {
457             List<Object> autoCompleteSuggestions = getAutoCompleteSuggestions();
458             return (autoCompleteSuggestions.size() == 2)
459                     && autoCompleteSuggestions.contains("testTwo")
460                     && autoCompleteSuggestions.contains("testThree");
461         });
462     }
463 
464     @Test
refreshAutoCompleteResults_removeItem()465     public void refreshAutoCompleteResults_removeItem() throws Throwable {
466         List<String> suggestions = new ArrayList<>(
467                 ImmutableList.of("testOne", "testTwo", "testThree"));
468         mAdapter = new ArrayAdapter<>(
469                 mActivity, android.R.layout.simple_dropdown_item_1line, suggestions);
470 
471         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
472             mAutoCompleteTextView.setAdapter(mAdapter);
473             mAutoCompleteTextView.setText("testT");
474             mAutoCompleteTextView.refreshAutoCompleteResults();
475         });
476         PollingCheck.waitFor(() -> {
477             List<Object> autoCompleteSuggestions = getAutoCompleteSuggestions();
478             return (autoCompleteSuggestions.size() == 2)
479                     && autoCompleteSuggestions.contains("testTwo")
480                     && autoCompleteSuggestions.contains("testThree");
481         });
482 
483         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
484             mAdapter.remove("testThree");
485             mAutoCompleteTextView.refreshAutoCompleteResults();
486         });
487         PollingCheck.waitFor(() -> {
488             List<Object> autoCompleteSuggestions = getAutoCompleteSuggestions();
489             return (autoCompleteSuggestions.size() == 1)
490                     && autoCompleteSuggestions.contains("testTwo");
491         });
492     }
493 
494     @Test
refreshAutoCompleteResults_threshold_changeText()495     public void refreshAutoCompleteResults_threshold_changeText() throws Throwable {
496         List<String> suggestions = new ArrayList<>(
497                 ImmutableList.of("testOne", "testTwo", "testThree"));
498         mAdapter = new ArrayAdapter<String>(
499                 mActivity, android.R.layout.simple_dropdown_item_1line, suggestions);
500 
501         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
502             mAutoCompleteTextView.setThreshold(3);
503             mAutoCompleteTextView.setAdapter(mAdapter);
504             mAutoCompleteTextView.setText("tes");
505         });
506 
507         // Above Threshold.
508         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
509             mAutoCompleteTextView.setText("test");
510             mAutoCompleteTextView.refreshAutoCompleteResults();
511         });
512         assertThat(mAutoCompleteTextView.isPopupShowing()).isTrue();
513         assertThat(getAutoCompleteSuggestions()).containsExactly("testOne", "testTwo", "testThree");
514 
515         // At Threshold.
516         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
517             mAutoCompleteTextView.setText("tes");
518             mAutoCompleteTextView.refreshAutoCompleteResults();
519         });
520         assertThat(mAutoCompleteTextView.isPopupShowing()).isTrue();
521         assertThat(getAutoCompleteSuggestions()).containsExactly("testOne", "testTwo", "testThree");
522 
523         // Below Threshold.
524         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
525             mAutoCompleteTextView.setText("te");
526             mAutoCompleteTextView.refreshAutoCompleteResults();
527         });
528         assertThat(mAutoCompleteTextView.isPopupShowing()).isFalse();
529     }
530 
531     @Test
refreshAutoCompleteResults_changeThreshold()532     public void refreshAutoCompleteResults_changeThreshold() throws Throwable {
533         List<String> suggestions = new ArrayList<>(
534                 ImmutableList.of("testOne", "testTwo", "testThree"));
535         mAdapter = new ArrayAdapter<String>(mActivity, android.R.layout.simple_dropdown_item_1line,
536                 suggestions);
537 
538         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
539             mAutoCompleteTextView.setAdapter(mAdapter);
540             mAutoCompleteTextView.setText("test");
541         });
542 
543         // Above Threshold.
544         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
545             mAutoCompleteTextView.setThreshold(3);
546             mAutoCompleteTextView.refreshAutoCompleteResults();
547         });
548         assertThat(mAutoCompleteTextView.isPopupShowing()).isTrue();
549         assertThat(getAutoCompleteSuggestions()).containsExactly("testOne", "testTwo", "testThree");
550 
551         // At Threshold.
552         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
553             mAutoCompleteTextView.setThreshold(4);
554             mAutoCompleteTextView.refreshAutoCompleteResults();
555         });
556         assertThat(mAutoCompleteTextView.isPopupShowing()).isTrue();
557         assertThat(getAutoCompleteSuggestions()).containsExactly("testOne", "testTwo", "testThree");
558 
559         // Below Threshold.
560         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
561             mAutoCompleteTextView.setThreshold(5);
562             mAutoCompleteTextView.refreshAutoCompleteResults();
563         });
564         assertThat(mAutoCompleteTextView.isPopupShowing()).isFalse();
565     }
566 
567     @Test
refreshAutoCompleteResults_dropDownAlwaysVisible()568     public void refreshAutoCompleteResults_dropDownAlwaysVisible() throws Throwable {
569         List<String> suggestions = new ArrayList<>(
570                 ImmutableList.of("testOne", "testTwo", "testThree"));
571         mAdapter = new ArrayAdapter<String>(mActivity, android.R.layout.simple_dropdown_item_1line,
572                 suggestions);
573 
574         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
575             mAutoCompleteTextView.setAdapter(mAdapter);
576             mAutoCompleteTextView.setDropDownAlwaysVisible(true);
577             mAutoCompleteTextView.setText("test");
578         });
579 
580         // Below Threshold.
581         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
582             mAutoCompleteTextView.setThreshold(5);
583             mAutoCompleteTextView.refreshAutoCompleteResults();
584         });
585         PollingCheck.waitFor(() -> mAutoCompleteTextView.isPopupShowing());
586     }
587 
588     @Test
refreshAutoCompleteResults_dropDownNotAlwaysVisible()589     public void refreshAutoCompleteResults_dropDownNotAlwaysVisible() throws Throwable {
590         List<String> suggestions = new ArrayList<>(
591                 ImmutableList.of("testOne", "testTwo", "testThree"));
592         mAdapter = new ArrayAdapter<String>(mActivity, android.R.layout.simple_dropdown_item_1line,
593                 suggestions);
594 
595         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
596             mAutoCompleteTextView.setAdapter(mAdapter);
597             mAutoCompleteTextView.setDropDownAlwaysVisible(false);
598             mAutoCompleteTextView.setText("test");
599         });
600 
601         // Below Threshold.
602         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
603             mAutoCompleteTextView.setThreshold(5);
604             mAutoCompleteTextView.refreshAutoCompleteResults();
605         });
606         assertThat(mAutoCompleteTextView.isPopupShowing()).isFalse();
607     }
608 
609     @Test
refreshAutoCompleteResults_popupCanBeUpdated()610     public void refreshAutoCompleteResults_popupCanBeUpdated() throws Throwable {
611         List<String> suggestions = new ArrayList<>(
612                 ImmutableList.of("testOne", "testTwo", "testThree"));
613         mAdapter = new ArrayAdapter<String>(mActivity, android.R.layout.simple_dropdown_item_1line,
614                 suggestions);
615 
616         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
617             mAutoCompleteTextView.setAdapter(mAdapter);
618             mAutoCompleteTextView.setDropDownAlwaysVisible(false);
619             mAutoCompleteTextView.setText("test");
620         });
621 
622         // Below Threshold.
623         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
624             mAutoCompleteTextView.setThreshold(5);
625             mAutoCompleteTextView.refreshAutoCompleteResults();
626         });
627         assertThat(mAutoCompleteTextView.isPopupShowing()).isFalse();
628     }
629 
630     @Test
refreshAutoCompleteResults()631     public void refreshAutoCompleteResults() throws Throwable {
632         List<String> suggestions = new ArrayList<>(ImmutableList.of("testOne", "testTwo"));
633         mAdapter = new ArrayAdapter<>(mActivity, android.R.layout.simple_dropdown_item_1line,
634                 suggestions);
635 
636         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
637             mAutoCompleteTextView.setAdapter(mAdapter);
638             mAutoCompleteTextView.setText("testT");
639             mAutoCompleteTextView.refreshAutoCompleteResults();
640         });
641         PollingCheck.waitFor(() -> {
642             List<Object> autoCompleteSuggestions = getAutoCompleteSuggestions();
643             return (autoCompleteSuggestions.size() == 1)
644                     && autoCompleteSuggestions.contains("testTwo");
645         });
646 
647         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
648             mAdapter.add("testThree");
649             mAutoCompleteTextView.refreshAutoCompleteResults();
650         });
651         PollingCheck.waitFor(() -> {
652             List<Object> autoCompleteSuggestions = getAutoCompleteSuggestions();
653             return (autoCompleteSuggestions.size() == 2)
654                     && autoCompleteSuggestions.contains("testTwo")
655                     && autoCompleteSuggestions.contains("testThree");
656         });
657     }
658 
659     @UiThreadTest
660     @Test
setInputMethodMode_fromFocussable()661     public void setInputMethodMode_fromFocussable() {
662         mAutoCompleteTextView.setInputMethodMode(INPUT_METHOD_FROM_FOCUSABLE);
663         assertThat(mAutoCompleteTextView.getInputMethodMode())
664                 .isEqualTo(INPUT_METHOD_FROM_FOCUSABLE);
665     }
666 
667     @UiThreadTest
668     @Test
setInputMethodMode_Needed()669     public void setInputMethodMode_Needed() {
670         mAutoCompleteTextView.setInputMethodMode(INPUT_METHOD_NEEDED);
671         assertThat(mAutoCompleteTextView.getInputMethodMode()).isEqualTo(INPUT_METHOD_NEEDED);
672     }
673 
674     @UiThreadTest
675     @Test
setInputMethodMode_NotNeeded()676     public void setInputMethodMode_NotNeeded() {
677         mAutoCompleteTextView.setInputMethodMode(INPUT_METHOD_NOT_NEEDED);
678         assertThat(mAutoCompleteTextView.getInputMethodMode()).isEqualTo(INPUT_METHOD_NOT_NEEDED);
679     }
680 
681     @UiThreadTest
682     @Test
testReplaceText()683     public void testReplaceText() {
684         final TextWatcher mockTextWatcher = mock(TextWatcher.class);
685         mMockAutoCompleteTextView.addTextChangedListener(mockTextWatcher);
686         verify(mockTextWatcher, never()).onTextChanged(any(CharSequence.class),
687                 anyInt(), anyInt(), anyInt());
688 
689         mMockAutoCompleteTextView.replaceText("Text");
690         assertEquals("Text", mMockAutoCompleteTextView.getText().toString());
691         verify(mockTextWatcher, times(1)).onTextChanged(sameCharSequence("Text"),
692                 eq(0), eq(0), eq("Text".length()));
693 
694         mMockAutoCompleteTextView.replaceText("Another");
695         assertEquals("Another", mMockAutoCompleteTextView.getText().toString());
696         verify(mockTextWatcher, times(1)).onTextChanged(sameCharSequence("Another"),
697                 eq(0), eq("Text".length()), eq("Another".length()));
698     }
699 
700     @UiThreadTest
701     @Test
testSetFrame()702     public void testSetFrame() {
703         assertTrue(mMockAutoCompleteTextView.setFrame(0, 1, 2, 3));
704         assertEquals(0, mMockAutoCompleteTextView.getLeft());
705         assertEquals(1, mMockAutoCompleteTextView.getTop());
706         assertEquals(2, mMockAutoCompleteTextView.getRight());
707         assertEquals(3, mMockAutoCompleteTextView.getBottom());
708 
709         // If the values are the same as old ones, function will return false
710         assertFalse(mMockAutoCompleteTextView.setFrame(0, 1, 2, 3));
711         assertEquals(0, mMockAutoCompleteTextView.getLeft());
712         assertEquals(1, mMockAutoCompleteTextView.getTop());
713         assertEquals(2, mMockAutoCompleteTextView.getRight());
714         assertEquals(3, mMockAutoCompleteTextView.getBottom());
715 
716         // If the values are not the same as old ones, function will return true
717         assertTrue(mMockAutoCompleteTextView.setFrame(2, 3, 4, 5));
718         assertEquals(2, mMockAutoCompleteTextView.getLeft());
719         assertEquals(3, mMockAutoCompleteTextView.getTop());
720         assertEquals(4, mMockAutoCompleteTextView.getRight());
721         assertEquals(5, mMockAutoCompleteTextView.getBottom());
722     }
723 
724     @UiThreadTest
725     @Test
testGetThreshold()726     public void testGetThreshold() {
727         assertEquals(1, mAutoCompleteTextView.getThreshold());
728         mAutoCompleteTextView.setThreshold(3);
729         assertEquals(3, mAutoCompleteTextView.getThreshold());
730 
731         // Test negative value input
732         mAutoCompleteTextView.setThreshold(-5);
733         assertEquals(1, mAutoCompleteTextView.getThreshold());
734 
735         // Test zero
736         mAutoCompleteTextView.setThreshold(0);
737         assertEquals(1, mAutoCompleteTextView.getThreshold());
738     }
739 
740     @UiThreadTest
741     @Test
testAccessValidater()742     public void testAccessValidater() {
743         final MockValidator validator = new MockValidator();
744 
745         assertNull(mAutoCompleteTextView.getValidator());
746         mAutoCompleteTextView.setValidator(validator);
747         assertSame(validator, mAutoCompleteTextView.getValidator());
748 
749         // Set to null
750         mAutoCompleteTextView.setValidator(null);
751         assertNull(mAutoCompleteTextView.getValidator());
752     }
753 
754     @Test
testOnFilterComplete()755     public void testOnFilterComplete() throws Throwable {
756         // Set Threshold to 4 characters
757         mAutoCompleteTextView.setThreshold(4);
758 
759         String testString = "";
760         if (mNumeric) {
761             // "tes" in case of 12-key(NUMERIC) keyboard
762             testString = "8337777";
763         } else {
764             testString = "tes";
765         }
766 
767         // Test the filter if the input string is not long enough to threshold
768         mActivityRule.runOnUiThread(() -> {
769                 mAutoCompleteTextView.setAdapter(mAdapter);
770                 mAutoCompleteTextView.setText("");
771                 mAutoCompleteTextView.requestFocus();
772         });
773         mInstrumentation.sendStringSync(testString);
774 
775         // onFilterComplete will close the popup.
776         PollingCheck.waitFor(() -> !mAutoCompleteTextView.isPopupShowing());
777 
778         if (mNumeric) {
779             // "that" in case of 12-key(NUMERIC) keyboard
780             testString = "84428";
781         } else {
782             testString = "that";
783         }
784         mInstrumentation.sendStringSync(testString);
785         PollingCheck.waitFor(() -> !mAutoCompleteTextView.isPopupShowing());
786 
787         // Test the expected filter matching scene
788         mActivityRule.runOnUiThread(() -> {
789                 mAutoCompleteTextView.setFocusable(true);
790                 mAutoCompleteTextView.requestFocus();
791                 mAutoCompleteTextView.setText("");
792         });
793         if (mNumeric) {
794             // "test" in case of 12-key(NUMERIC) keyboard
795             mInstrumentation.sendStringSync("83377778");
796         } else {
797             mInstrumentation.sendStringSync("test");
798         }
799         assertTrue(mAutoCompleteTextView.hasFocus());
800         assertTrue(mAutoCompleteTextView.hasWindowFocus());
801         PollingCheck.waitFor(() -> mAutoCompleteTextView.isPopupShowing());
802     }
803 
804     @Test
testPerformFiltering()805     public void testPerformFiltering() throws Throwable {
806         if (isTvMode()) {
807             return;
808         }
809         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
810             mAutoCompleteTextView.setAdapter(mAdapter);
811             mAutoCompleteTextView.setValidator(mValidator);
812 
813             mAutoCompleteTextView.setText("test");
814             mAutoCompleteTextView.setFocusable(true);
815             mAutoCompleteTextView.requestFocus();
816             mAutoCompleteTextView.showDropDown();
817         });
818         assertTrue(mAutoCompleteTextView.isPopupShowing());
819 
820         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
821         // KeyBack will close the popup.
822         assertFalse(mAutoCompleteTextView.isPopupShowing());
823 
824         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
825             mAutoCompleteTextView.showDropDown();
826         });
827         assertTrue(mAutoCompleteTextView.isPopupShowing());
828 
829         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_ESCAPE);
830         // KeyEscape will also close the popup.
831         assertFalse(mAutoCompleteTextView.isPopupShowing());
832 
833         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
834             mAutoCompleteTextView.dismissDropDown();
835             mAutoCompleteTextView.setText(STRING_TEST);
836         });
837 
838         assertEquals(STRING_TEST, mAutoCompleteTextView.getText().toString());
839         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
840         // If the popup is closed, onKeyDown will invoke performValidation.
841         assertEquals(STRING_VALIDATED, mAutoCompleteTextView.getText().toString());
842 
843         final MockAdapter<String> adapter = new MockAdapter<String>(mActivity,
844                 android.R.layout.simple_dropdown_item_1line, WORDS);
845 
846         // Set Threshold to 4 characters onKeyDown
847         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
848             mAutoCompleteTextView.setAdapter(adapter);
849             mAutoCompleteTextView.requestFocus();
850             mAutoCompleteTextView.setText("");
851         });
852         // Create and get the filter.
853         final MockFilter filter = (MockFilter) adapter.getFilter();
854 
855         // performFiltering will be indirectly invoked by onKeyDown
856         assertNull(filter.getResult());
857         // 12-key support
858         if (mNumeric) {
859             // "numeric" in case of 12-key(NUMERIC) keyboard
860             mInstrumentation.sendStringSync("6688633777444222");
861             PollingCheck.waitFor(() -> "numeric".equals(filter.getResult()));
862         } else {
863             SystemClock.sleep(200);
864             mInstrumentation.sendStringSync(STRING_TEST);
865             PollingCheck.waitFor(() -> STRING_TEST.equals(filter.getResult()));
866         }
867     }
868 
869     @Test
testPerformCompletionWithDPad()870     public void testPerformCompletionWithDPad() throws Throwable {
871         if (isTvMode()) {
872             return;
873         }
874         final AdapterView.OnItemClickListener mockItemClickListener =
875                 mock(AdapterView.OnItemClickListener.class);
876         assertFalse(mAutoCompleteTextView.isPerformingCompletion());
877 
878         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
879             mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
880             mAutoCompleteTextView.setAdapter(mAdapter);
881             mAutoCompleteTextView.requestFocus();
882             mAutoCompleteTextView.showDropDown();
883         });
884         assertFalse(mAutoCompleteTextView.isPerformingCompletion());
885 
886         // Key is ENTER, will invoke completion
887         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
888         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_ENTER);
889         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, null);
890         verify(mockItemClickListener, times(1)).onItemClick(any(AdapterView.class), any(View.class),
891                 eq(0), eq(0L));
892         assertEquals(WORDS[0], mAutoCompleteTextView.getText().toString());
893 
894         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView,
895                 mAutoCompleteTextView::showDropDown);
896         // Key is NUMPAD_ENTER, will invoke completion
897         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
898         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_NUMPAD_ENTER);
899         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, null);
900         verify(mockItemClickListener, times(2)).onItemClick(any(AdapterView.class), any(View.class),
901                 eq(0), eq(0L));
902         assertEquals(WORDS[0], mAutoCompleteTextView.getText().toString());
903 
904         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView,
905                 mAutoCompleteTextView::showDropDown);
906         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
907         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
908         verify(mockItemClickListener, times(3)).onItemClick(any(AdapterView.class), any(View.class),
909                 eq(0), eq(0L));
910         assertEquals(WORDS[0], mAutoCompleteTextView.getText().toString());
911         assertFalse(mAutoCompleteTextView.isPerformingCompletion());
912 
913         mActivityRule.runOnUiThread(mAutoCompleteTextView::showDropDown);
914         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
915         // Test normal key code.
916         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_0);
917         verifyNoMoreInteractions(mockItemClickListener);
918         assertNotSame("", mAutoCompleteTextView.getText().toString());
919         assertFalse(mAutoCompleteTextView.isPerformingCompletion());
920 
921         // Test the method on the scene of popup is closed.
922         mActivityRule.runOnUiThread(mAutoCompleteTextView::dismissDropDown);
923 
924         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
925         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_ENTER);
926         verifyNoMoreInteractions(mockItemClickListener);
927         assertNotSame("", mAutoCompleteTextView.getText().toString());
928         assertFalse(mAutoCompleteTextView.isPerformingCompletion());
929     }
930 
931     @Test
testPerformCompletionExplicit()932     public void testPerformCompletionExplicit() throws Throwable {
933         final AdapterView.OnItemClickListener mockItemClickListener =
934                 mock(AdapterView.OnItemClickListener.class);
935         assertFalse(mAutoCompleteTextView.isPerformingCompletion());
936 
937         // Create a custom watcher that checks isPerformingCompletion to return true
938         // in the "middle" of the performCompletion processing. We also spy on this watcher
939         // to make sure that its onTextChanged is invoked.
940         final TextWatcher myTextWatcher = new MyTextWatcher(WORDS[1]);
941         final TextWatcher spyTextWatcher = spy(myTextWatcher);
942         mAutoCompleteTextView.addTextChangedListener(spyTextWatcher);
943 
944         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
945             mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
946             mAutoCompleteTextView.setAdapter(mAdapter);
947             mAutoCompleteTextView.requestFocus();
948             mAutoCompleteTextView.showDropDown();
949         });
950 
951         assertTrue(mAutoCompleteTextView.isPopupShowing());
952         assertFalse(mAutoCompleteTextView.isPerformingCompletion());
953 
954         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
955         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
956         mActivityRule.runOnUiThread(mAutoCompleteTextView::performCompletion);
957         verify(mockItemClickListener, times(1)).onItemClick(any(AdapterView.class), any(View.class),
958                 eq(1), eq(1L));
959         assertEquals(WORDS[1], mAutoCompleteTextView.getText().toString());
960         assertFalse(mAutoCompleteTextView.isPerformingCompletion());
961         assertFalse(mAutoCompleteTextView.isPopupShowing());
962 
963         verify(spyTextWatcher, atLeastOnce()).onTextChanged(sameCharSequence(WORDS[1]),
964                 eq(0), eq(0), eq(WORDS[1].length()));
965         verifyNoMoreInteractions(mockItemClickListener);
966     }
967 
968     @Test
testSetTextWithCompletion()969     public void testSetTextWithCompletion() throws Throwable {
970         final AdapterView.OnItemClickListener mockItemClickListener =
971                 mock(AdapterView.OnItemClickListener.class);
972 
973         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
974             mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
975             mAutoCompleteTextView.setAdapter(mAdapter);
976         });
977         PollingCheck.waitFor(() -> !mAutoCompleteTextView.isPopupShowing());
978 
979         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView,
980                 () -> mAutoCompleteTextView.setText("testO", true));
981         PollingCheck.waitFor(() -> mAutoCompleteTextView.isPopupShowing());
982 
983         verifyZeroInteractions(mockItemClickListener);
984     }
985 
986     @Test
testSetTextWithNoCompletion()987     public void testSetTextWithNoCompletion() throws Throwable {
988         final AdapterView.OnItemClickListener mockItemClickListener =
989                 mock(AdapterView.OnItemClickListener.class);
990 
991         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
992             mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
993             mAutoCompleteTextView.setAdapter(mAdapter);
994         });
995 
996         assertFalse(mAutoCompleteTextView.isPopupShowing());
997 
998         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView,
999                 () -> mAutoCompleteTextView.setText("testO", false));
1000 
1001         assertFalse(mAutoCompleteTextView.isPopupShowing());
1002         verifyZeroInteractions(mockItemClickListener);
1003     }
1004 
1005     @UiThreadTest
1006     @Test
testPerformValidation()1007     public void testPerformValidation() {
1008         final CharSequence text = "this";
1009 
1010         mAutoCompleteTextView.setValidator(mValidator);
1011         mAutoCompleteTextView.setAdapter((ArrayAdapter<String>) null);
1012         mAutoCompleteTextView.setText(text);
1013         mAutoCompleteTextView.performValidation();
1014 
1015         assertEquals(STRING_VALIDATED, mAutoCompleteTextView.getText().toString());
1016         mAutoCompleteTextView.setValidator(null);
1017     }
1018 
1019     @UiThreadTest
1020     @Test
testAccessCompletionHint()1021     public void testAccessCompletionHint() {
1022         mAutoCompleteTextView.setCompletionHint("TEST HINT");
1023         assertEquals("TEST HINT", mAutoCompleteTextView.getCompletionHint());
1024 
1025         mAutoCompleteTextView.setCompletionHint(null);
1026         assertNull(mAutoCompleteTextView.getCompletionHint());
1027     }
1028 
1029     @Test
testAccessListSelection()1030     public void testAccessListSelection() throws Throwable {
1031         final AdapterView.OnItemClickListener mockItemClickListener =
1032                 mock(AdapterView.OnItemClickListener.class);
1033 
1034         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
1035             mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
1036             mAutoCompleteTextView.setAdapter(mAdapter);
1037             mAutoCompleteTextView.requestFocus();
1038             mAutoCompleteTextView.showDropDown();
1039         });
1040 
1041         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mAutoCompleteTextView, () -> {
1042             mAutoCompleteTextView.setListSelection(1);
1043             assertEquals(1, mAutoCompleteTextView.getListSelection());
1044 
1045             mAutoCompleteTextView.setListSelection(2);
1046             assertEquals(2, mAutoCompleteTextView.getListSelection());
1047 
1048             mAutoCompleteTextView.clearListSelection();
1049             assertEquals(2, mAutoCompleteTextView.getListSelection());
1050         });
1051     }
1052 
1053     @UiThreadTest
1054     @Test
testAccessDropDownAnchor()1055     public void testAccessDropDownAnchor() {
1056         mAutoCompleteTextView.setDropDownAnchor(View.NO_ID);
1057         assertEquals(View.NO_ID, mAutoCompleteTextView.getDropDownAnchor());
1058 
1059         mAutoCompleteTextView.setDropDownAnchor(0x5555);
1060         assertEquals(0x5555, mAutoCompleteTextView.getDropDownAnchor());
1061     }
1062 
1063     @UiThreadTest
1064     @Test
testAccessDropDownWidth()1065     public void testAccessDropDownWidth() {
1066         mAutoCompleteTextView.setDropDownWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
1067         assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, mAutoCompleteTextView.getDropDownWidth());
1068 
1069         mAutoCompleteTextView.setDropDownWidth(ViewGroup.LayoutParams.MATCH_PARENT);
1070         assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, mAutoCompleteTextView.getDropDownWidth());
1071     }
1072 
getAutoCompleteSuggestions()1073     private List<Object> getAutoCompleteSuggestions() {
1074         int count = mAutoCompleteTextView.getAdapter().getCount();
1075         List<Object> autoCompleteSuggestions = new ArrayList<>(count);
1076         for (int index = 0; index < count; index++) {
1077             autoCompleteSuggestions.add(mAutoCompleteTextView.getAdapter().getItem(index));
1078         }
1079         return autoCompleteSuggestions;
1080     }
1081 
1082     private class MockValidator implements AutoCompleteTextView.Validator {
fixText(CharSequence invalidText)1083         public CharSequence fixText(CharSequence invalidText) {
1084             return STRING_VALIDATED;
1085         }
1086 
isValid(CharSequence text)1087         public boolean isValid(CharSequence text) {
1088             return (text == STRING_TEST);
1089         }
1090     }
1091 
1092     public static class MockAutoCompleteTextView extends AutoCompleteTextView {
MockAutoCompleteTextView(Context context)1093         public MockAutoCompleteTextView(Context context) {
1094             super(context);
1095         }
1096 
MockAutoCompleteTextView(Context context, AttributeSet attrs)1097         public MockAutoCompleteTextView(Context context, AttributeSet attrs) {
1098             super(context, attrs);
1099         }
1100 
1101         @Override
convertSelectionToString(Object selectedItem)1102         protected CharSequence convertSelectionToString(Object selectedItem) {
1103             return super.convertSelectionToString(selectedItem);
1104         }
1105 
1106         @Override
getFilter()1107         protected Filter getFilter() {
1108             return super.getFilter();
1109         }
1110 
1111         @Override
onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect)1112         protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
1113             super.onFocusChanged(focused, direction, previouslyFocusedRect);
1114         }
1115 
1116         @Override
performFiltering(CharSequence text, int keyCode)1117         protected void performFiltering(CharSequence text, int keyCode) {
1118             super.performFiltering(text, keyCode);
1119         }
1120 
1121         @Override
replaceText(CharSequence text)1122         protected void replaceText(CharSequence text) {
1123             super.replaceText(text);
1124         }
1125 
1126         @Override
setFrame(int l, int t, int r, int b)1127         protected boolean setFrame(int l, int t, int r, int b) {
1128             return super.setFrame(l, t, r, b);
1129         }
1130     }
1131 
1132     private static class MockFilter extends Filter {
1133         private String mFilterResult;
1134 
1135         @Override
performFiltering(CharSequence constraint)1136         protected FilterResults performFiltering(CharSequence constraint) {
1137             if (constraint != null) {
1138                 mFilterResult = constraint.toString();
1139             }
1140             return null;
1141         }
1142 
1143         @Override
publishResults(CharSequence constraint, FilterResults results)1144         protected void publishResults(CharSequence constraint, FilterResults results) {
1145         }
1146 
getResult()1147         public String getResult() {
1148             return mFilterResult;
1149         }
1150     }
1151 
1152     private static class MockAdapter<T> extends ArrayAdapter<T> implements Filterable {
1153         private MockFilter mFilter;
1154 
MockAdapter(Context context, int textViewResourceId, T[] objects)1155         public MockAdapter(Context context, int textViewResourceId, T[] objects) {
1156             super(context, textViewResourceId, objects);
1157         }
1158 
1159         @Override
getFilter()1160         public Filter getFilter() {
1161             if (mFilter == null) {
1162                 mFilter = new MockFilter();
1163             }
1164             return mFilter;
1165         }
1166     }
1167 }
1168