blob: 5b969d31e9df7ce927b79c14ede9727dfc3a6f17 [file] [log] [blame]
/*
* Copyright (C) 2008 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.widget.cts;
import static com.android.compatibility.common.util.WidgetTestUtils.sameCharSequence;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import android.app.Activity;
import android.app.Instrumentation;
import android.app.UiModeManager;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.SystemClock;
import android.support.test.InstrumentationRegistry;
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.MediumTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Xml;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.AutoCompleteTextView.Validator;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.cts.util.TestUtils;
import com.android.compatibility.common.util.PollingCheck;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.xmlpull.v1.XmlPullParser;
@MediumTest
@RunWith(AndroidJUnit4.class)
public class AutoCompleteTextViewTest {
private final static String[] WORDS =
new String[] { "testOne", "testTwo", "testThree", "testFour" };
private final static String STRING_TEST = "To be tested";
private final static String STRING_VALIDATED = "String Validated";
private final static String STRING_CHECK = "To be checked";
private Activity mActivity;
private Instrumentation mInstrumentation;
private AutoCompleteTextView mAutoCompleteTextView;
private MockAutoCompleteTextView mMockAutoCompleteTextView;
private boolean mNumeric = false;
private ArrayAdapter<String> mAdapter;
@Rule
public ActivityTestRule<AutoCompleteCtsActivity> mActivityRule =
new ActivityTestRule<>(AutoCompleteCtsActivity.class);
private final Validator mValidator = new Validator() {
public CharSequence fixText(CharSequence invalidText) {
return STRING_VALIDATED;
}
public boolean isValid(CharSequence text) {
return false;
}
};
protected class MyTextWatcher implements TextWatcher {
private CharSequence mExpectedAfter;
public MyTextWatcher(CharSequence expectedAfter) {
mExpectedAfter = expectedAfter;
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
assertEquals(mExpectedAfter.toString(), s.toString());
// This watcher is expected to be notified in the middle of completion
assertTrue(mAutoCompleteTextView.isPerformingCompletion());
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void afterTextChanged(Editable s) {
}
}
@Before
public void setup() {
mActivity = mActivityRule.getActivity();
PollingCheck.waitFor(mActivity::hasWindowFocus);
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mAutoCompleteTextView = (AutoCompleteTextView) mActivity
.findViewById(R.id.autocompletetv_edit);
mMockAutoCompleteTextView = (MockAutoCompleteTextView) mActivity
.findViewById(R.id.autocompletetv_custom);
mAdapter = new ArrayAdapter<>(mActivity,
android.R.layout.simple_dropdown_item_1line, WORDS);
KeyCharacterMap keymap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
if (keymap.getKeyboardType() == KeyCharacterMap.NUMERIC) {
mNumeric = true;
}
}
boolean isTvMode() {
UiModeManager uiModeManager = (UiModeManager) mActivity.getSystemService(
Context.UI_MODE_SERVICE);
return uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION;
}
@Test
public void testConstructor() {
XmlPullParser parser;
new AutoCompleteTextView(mActivity);
new AutoCompleteTextView(mActivity, null);
new AutoCompleteTextView(mActivity, null, android.R.attr.autoCompleteTextViewStyle);
new AutoCompleteTextView(mActivity, null, 0,
android.R.style.Widget_DeviceDefault_AutoCompleteTextView);
new AutoCompleteTextView(mActivity, null, 0,
android.R.style.Widget_DeviceDefault_Light_AutoCompleteTextView);
new AutoCompleteTextView(mActivity, null, 0,
android.R.style.Widget_Material_AutoCompleteTextView);
new AutoCompleteTextView(mActivity, null, 0,
android.R.style.Widget_Material_Light_AutoCompleteTextView);
final Resources.Theme popupTheme = mActivity.getResources().newTheme();
popupTheme.applyStyle(android.R.style.Theme_Material, true);
new AutoCompleteTextView(mActivity, null, 0,
android.R.style.Widget_Material_Light_AutoCompleteTextView, popupTheme);
// new the AutoCompleteTextView instance
parser = mActivity.getResources().getXml(R.layout.simple_dropdown_item_1line);
AttributeSet attributeSet = Xml.asAttributeSet(parser);
new AutoCompleteTextView(mActivity, attributeSet);
// new the AutoCompleteTextView instance
parser = mActivity.getResources().getXml(R.layout.framelayout_layout);
attributeSet = Xml.asAttributeSet(parser);
new AutoCompleteTextView(mActivity, attributeSet, 0);
// Test for negative style resource ID
new AutoCompleteTextView(mActivity, attributeSet, -1);
// Test null AttributeSet
new AutoCompleteTextView(mActivity, null, -1);
}
@Test(expected=NullPointerException.class)
public void testConstructorWithNullContext() {
XmlPullParser parser = mActivity.getResources().getXml(R.layout.simple_dropdown_item_1line);
AttributeSet attributeSet = Xml.asAttributeSet(parser);
new AutoCompleteTextView(null, attributeSet, 0);
}
@Test
public void testEnoughToFilter() throws Throwable {
mAutoCompleteTextView.setThreshold(3);
assertEquals(3, mAutoCompleteTextView.getThreshold());
mActivityRule.runOnUiThread(() -> mAutoCompleteTextView.setText("TryToTest"));
mInstrumentation.waitForIdleSync();
assertTrue(mAutoCompleteTextView.enoughToFilter());
mActivityRule.runOnUiThread(() -> mAutoCompleteTextView.setText("No"));
mInstrumentation.waitForIdleSync();
assertFalse(mAutoCompleteTextView.enoughToFilter());
}
@UiThreadTest
@Test
public void testAccessAdapter() {
mAutoCompleteTextView.setAdapter(null);
assertNull(mAutoCompleteTextView.getAdapter());
mAutoCompleteTextView.setAdapter(mAdapter);
assertSame(mAdapter, mAutoCompleteTextView.getAdapter());
// Re-set adapter to null
mAutoCompleteTextView.setAdapter(null);
assertNull(mAutoCompleteTextView.getAdapter());
}
@UiThreadTest
@Test
public void testAccessFilter() {
MockAutoCompleteTextView autoCompleteTextView = new MockAutoCompleteTextView(mActivity);
// Set Threshold to 4 characters
autoCompleteTextView.setThreshold(4);
autoCompleteTextView.setAdapter(null);
assertNull(autoCompleteTextView.getAdapter());
assertNull(autoCompleteTextView.getFilter());
Filter filter = mAdapter.getFilter();
assertNotNull(filter);
autoCompleteTextView.setAdapter(mAdapter);
assertSame(mAdapter, autoCompleteTextView.getAdapter());
assertSame(filter, autoCompleteTextView.getFilter());
// Re-set adapter to null
autoCompleteTextView.setAdapter(null);
assertNull(autoCompleteTextView.getAdapter());
assertNull(autoCompleteTextView.getFilter());
}
@UiThreadTest
@Test
public void testAccessItemClickListener() {
final AdapterView.OnItemClickListener mockItemClickListener =
mock(AdapterView.OnItemClickListener.class);
// To ensure null listener
mAutoCompleteTextView.setOnItemClickListener(null);
assertNull(mAutoCompleteTextView.getItemClickListener());
assertNull(mAutoCompleteTextView.getOnItemClickListener());
mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
assertSame(mockItemClickListener, mAutoCompleteTextView.getItemClickListener());
assertSame(mockItemClickListener, mAutoCompleteTextView.getOnItemClickListener());
verifyZeroInteractions(mockItemClickListener);
// re-clear listener by setOnItemClickListener
mAutoCompleteTextView.setOnItemClickListener(null);
assertNull(mAutoCompleteTextView.getItemClickListener());
assertNull(mAutoCompleteTextView.getOnItemClickListener());
verifyZeroInteractions(mockItemClickListener);
}
@UiThreadTest
@Test
public void testAccessItemSelectedListener() {
final AdapterView.OnItemSelectedListener mockItemSelectedListener =
mock(AdapterView.OnItemSelectedListener.class);
// To ensure null listener
mAutoCompleteTextView.setOnItemSelectedListener(null);
assertNull(mAutoCompleteTextView.getItemSelectedListener());
assertNull(mAutoCompleteTextView.getOnItemSelectedListener());
mAutoCompleteTextView.setOnItemSelectedListener(mockItemSelectedListener);
assertSame(mockItemSelectedListener, mAutoCompleteTextView.getItemSelectedListener());
assertSame(mockItemSelectedListener, mAutoCompleteTextView.getOnItemSelectedListener());
verifyZeroInteractions(mockItemSelectedListener);
//re-clear listener by setOnItemClickListener
mAutoCompleteTextView.setOnItemSelectedListener(null);
assertNull(mAutoCompleteTextView.getItemSelectedListener());
assertNull(mAutoCompleteTextView.getOnItemSelectedListener());
verifyZeroInteractions(mockItemSelectedListener);
}
@UiThreadTest
@Test
public void testConvertSelectionToString() {
MockAutoCompleteTextView autoCompleteTextView = new MockAutoCompleteTextView(mActivity);
// Set Threshold to 4 characters
autoCompleteTextView.setThreshold(4);
autoCompleteTextView.setAdapter(mAdapter);
assertNotNull(autoCompleteTextView.getAdapter());
assertEquals("", autoCompleteTextView.convertSelectionToString(null));
assertEquals(STRING_TEST, autoCompleteTextView.convertSelectionToString(STRING_TEST));
}
@UiThreadTest
@Test
public void testOnTextChanged() {
final TextWatcher mockTextWatcher = mock(TextWatcher.class);
mAutoCompleteTextView.addTextChangedListener(mockTextWatcher);
verify(mockTextWatcher, never()).onTextChanged(any(CharSequence.class),
anyInt(), anyInt(), anyInt());
mAutoCompleteTextView.setText(STRING_TEST);
verify(mockTextWatcher, times(1)).onTextChanged(sameCharSequence(STRING_TEST),
eq(0), eq(0), eq(STRING_TEST.length()));
// Test replacing text.
mAutoCompleteTextView.setText(STRING_CHECK);
verify(mockTextWatcher, times(1)).onTextChanged(sameCharSequence(STRING_CHECK),
eq(0), eq(STRING_TEST.length()), eq(STRING_CHECK.length()));
}
@UiThreadTest
@Test
public void testPopupWindow() {
final AutoCompleteTextView.OnDismissListener mockDismissListener =
mock(AutoCompleteTextView.OnDismissListener.class);
mAutoCompleteTextView.setOnDismissListener(mockDismissListener);
assertFalse(mAutoCompleteTextView.isPopupShowing());
mAutoCompleteTextView.showDropDown();
assertTrue(mAutoCompleteTextView.isPopupShowing());
verifyZeroInteractions(mockDismissListener);
mAutoCompleteTextView.dismissDropDown();
assertFalse(mAutoCompleteTextView.isPopupShowing());
verify(mockDismissListener, times(1)).onDismiss();
mAutoCompleteTextView.showDropDown();
assertTrue(mAutoCompleteTextView.isPopupShowing());
verify(mockDismissListener, times(1)).onDismiss();
final MockValidator validator = new MockValidator();
mAutoCompleteTextView.setValidator(validator);
mAutoCompleteTextView.requestFocus();
mAutoCompleteTextView.showDropDown();
mAutoCompleteTextView.setText(STRING_TEST);
assertEquals(STRING_TEST, mAutoCompleteTextView.getText().toString());
// clearFocus will trigger onFocusChanged, and onFocusChanged will validate the text.
mAutoCompleteTextView.clearFocus();
assertFalse(mAutoCompleteTextView.isPopupShowing());
assertEquals(STRING_VALIDATED, mAutoCompleteTextView.getText().toString());
verify(mockDismissListener, times(2)).onDismiss();
verifyNoMoreInteractions(mockDismissListener);
}
@UiThreadTest
@Test
public void testDropDownMetrics() {
mAutoCompleteTextView.setAdapter(mAdapter);
final Resources res = mActivity.getResources();
final int dropDownWidth =
res.getDimensionPixelSize(R.dimen.autocomplete_textview_dropdown_width);
final int dropDownHeight =
res.getDimensionPixelSize(R.dimen.autocomplete_textview_dropdown_height);
final int dropDownOffsetHorizontal =
res.getDimensionPixelSize(R.dimen.autocomplete_textview_dropdown_offset_h);
final int dropDownOffsetVertical =
res.getDimensionPixelSize(R.dimen.autocomplete_textview_dropdown_offset_v);
mAutoCompleteTextView.setDropDownWidth(dropDownWidth);
mAutoCompleteTextView.setDropDownHeight(dropDownHeight);
mAutoCompleteTextView.setDropDownHorizontalOffset(dropDownOffsetHorizontal);
mAutoCompleteTextView.setDropDownVerticalOffset(dropDownOffsetVertical);
mAutoCompleteTextView.showDropDown();
assertEquals(dropDownWidth, mAutoCompleteTextView.getDropDownWidth());
assertEquals(dropDownHeight, mAutoCompleteTextView.getDropDownHeight());
assertEquals(dropDownOffsetHorizontal, mAutoCompleteTextView.getDropDownHorizontalOffset());
assertEquals(dropDownOffsetVertical, mAutoCompleteTextView.getDropDownVerticalOffset());
}
@Test
public void testDropDownBackground() throws Throwable {
mActivityRule.runOnUiThread(() -> mAutoCompleteTextView.setAdapter(mAdapter));
mActivityRule.runOnUiThread(() -> {
mAutoCompleteTextView.setDropDownBackgroundResource(R.drawable.blue_fill);
mAutoCompleteTextView.showDropDown();
});
mInstrumentation.waitForIdleSync();
Drawable dropDownBackground = mAutoCompleteTextView.getDropDownBackground();
TestUtils.assertAllPixelsOfColor("Drop down should be blue", dropDownBackground,
dropDownBackground.getBounds().width(), dropDownBackground.getBounds().height(),
false, Color.BLUE, 1, true);
mActivityRule.runOnUiThread(() -> {
mAutoCompleteTextView.dismissDropDown();
mAutoCompleteTextView.setDropDownBackgroundDrawable(
mActivity.getDrawable(R.drawable.yellow_fill));
mAutoCompleteTextView.showDropDown();
});
mInstrumentation.waitForIdleSync();
dropDownBackground = mAutoCompleteTextView.getDropDownBackground();
TestUtils.assertAllPixelsOfColor("Drop down should be yellow", dropDownBackground,
dropDownBackground.getBounds().width(), dropDownBackground.getBounds().height(),
false, Color.YELLOW, 1, true);
}
@UiThreadTest
@Test
public void testReplaceText() {
final TextWatcher mockTextWatcher = mock(TextWatcher.class);
mMockAutoCompleteTextView.addTextChangedListener(mockTextWatcher);
verify(mockTextWatcher, never()).onTextChanged(any(CharSequence.class),
anyInt(), anyInt(), anyInt());
mMockAutoCompleteTextView.replaceText("Text");
assertEquals("Text", mMockAutoCompleteTextView.getText().toString());
verify(mockTextWatcher, times(1)).onTextChanged(sameCharSequence("Text"),
eq(0), eq(0), eq("Text".length()));
mMockAutoCompleteTextView.replaceText("Another");
assertEquals("Another", mMockAutoCompleteTextView.getText().toString());
verify(mockTextWatcher, times(1)).onTextChanged(sameCharSequence("Another"),
eq(0), eq("Text".length()), eq("Another".length()));
}
@UiThreadTest
@Test
public void testSetFrame() {
assertTrue(mMockAutoCompleteTextView.setFrame(0, 1, 2, 3));
assertEquals(0, mMockAutoCompleteTextView.getLeft());
assertEquals(1, mMockAutoCompleteTextView.getTop());
assertEquals(2, mMockAutoCompleteTextView.getRight());
assertEquals(3, mMockAutoCompleteTextView.getBottom());
// If the values are the same as old ones, function will return false
assertFalse(mMockAutoCompleteTextView.setFrame(0, 1, 2, 3));
assertEquals(0, mMockAutoCompleteTextView.getLeft());
assertEquals(1, mMockAutoCompleteTextView.getTop());
assertEquals(2, mMockAutoCompleteTextView.getRight());
assertEquals(3, mMockAutoCompleteTextView.getBottom());
// If the values are not the same as old ones, function will return true
assertTrue(mMockAutoCompleteTextView.setFrame(2, 3, 4, 5));
assertEquals(2, mMockAutoCompleteTextView.getLeft());
assertEquals(3, mMockAutoCompleteTextView.getTop());
assertEquals(4, mMockAutoCompleteTextView.getRight());
assertEquals(5, mMockAutoCompleteTextView.getBottom());
}
@UiThreadTest
@Test
public void testGetThreshold() {
assertEquals(1, mAutoCompleteTextView.getThreshold());
mAutoCompleteTextView.setThreshold(3);
assertEquals(3, mAutoCompleteTextView.getThreshold());
// Test negative value input
mAutoCompleteTextView.setThreshold(-5);
assertEquals(1, mAutoCompleteTextView.getThreshold());
// Test zero
mAutoCompleteTextView.setThreshold(0);
assertEquals(1, mAutoCompleteTextView.getThreshold());
}
@UiThreadTest
@Test
public void testAccessValidater() {
final MockValidator validator = new MockValidator();
assertNull(mAutoCompleteTextView.getValidator());
mAutoCompleteTextView.setValidator(validator);
assertSame(validator, mAutoCompleteTextView.getValidator());
// Set to null
mAutoCompleteTextView.setValidator(null);
assertNull(mAutoCompleteTextView.getValidator());
}
@Test
public void testOnFilterComplete() throws Throwable {
// Set Threshold to 4 characters
mAutoCompleteTextView.setThreshold(4);
String testString = "";
if (mNumeric) {
// "tes" in case of 12-key(NUMERIC) keyboard
testString = "8337777";
} else {
testString = "tes";
}
// Test the filter if the input string is not long enough to threshold
mActivityRule.runOnUiThread(() -> {
mAutoCompleteTextView.setAdapter(mAdapter);
mAutoCompleteTextView.setText("");
mAutoCompleteTextView.requestFocus();
});
mInstrumentation.sendStringSync(testString);
// onFilterComplete will close the popup.
PollingCheck.waitFor(() -> !mAutoCompleteTextView.isPopupShowing());
if (mNumeric) {
// "that" in case of 12-key(NUMERIC) keyboard
testString = "84428";
} else {
testString = "that";
}
mInstrumentation.sendStringSync(testString);
PollingCheck.waitFor(() -> !mAutoCompleteTextView.isPopupShowing());
// Test the expected filter matching scene
mActivityRule.runOnUiThread(() -> {
mAutoCompleteTextView.setFocusable(true);
mAutoCompleteTextView.requestFocus();
mAutoCompleteTextView.setText("");
});
if (mNumeric) {
// "test" in case of 12-key(NUMERIC) keyboard
mInstrumentation.sendStringSync("83377778");
} else {
mInstrumentation.sendStringSync("test");
}
assertTrue(mAutoCompleteTextView.hasFocus());
assertTrue(mAutoCompleteTextView.hasWindowFocus());
PollingCheck.waitFor(() -> mAutoCompleteTextView.isPopupShowing());
}
@Test
public void testPerformFiltering() throws Throwable {
if (isTvMode()) {
return;
}
mActivityRule.runOnUiThread(() -> {
mAutoCompleteTextView.setAdapter(mAdapter);
mAutoCompleteTextView.setValidator(mValidator);
mAutoCompleteTextView.setText("test");
mAutoCompleteTextView.setFocusable(true);
mAutoCompleteTextView.requestFocus();
mAutoCompleteTextView.showDropDown();
});
mInstrumentation.waitForIdleSync();
assertTrue(mAutoCompleteTextView.isPopupShowing());
mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
// KeyBack will close the popup.
assertFalse(mAutoCompleteTextView.isPopupShowing());
mActivityRule.runOnUiThread(() -> {
mAutoCompleteTextView.dismissDropDown();
mAutoCompleteTextView.setText(STRING_TEST);
});
mInstrumentation.waitForIdleSync();
assertEquals(STRING_TEST, mAutoCompleteTextView.getText().toString());
mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
// If the popup is closed, onKeyDown will invoke performValidation.
assertEquals(STRING_VALIDATED, mAutoCompleteTextView.getText().toString());
final MockAdapter<String> adapter = new MockAdapter<String>(mActivity,
android.R.layout.simple_dropdown_item_1line, WORDS);
// Set Threshold to 4 charactersonKeyDown
mActivityRule.runOnUiThread(() -> {
mAutoCompleteTextView.setAdapter(adapter);
mAutoCompleteTextView.requestFocus();
mAutoCompleteTextView.setText("");
});
mInstrumentation.waitForIdleSync();
// Create and get the filter.
final MockFilter filter = (MockFilter) adapter.getFilter();
// performFiltering will be indirectly invoked by onKeyDown
assertNull(filter.getResult());
// 12-key support
if (mNumeric) {
// "numeric" in case of 12-key(NUMERIC) keyboard
mInstrumentation.sendStringSync("6688633777444222");
PollingCheck.waitFor(() -> "numeric".equals(filter.getResult()));
} else {
SystemClock.sleep(200);
mInstrumentation.sendStringSync(STRING_TEST);
PollingCheck.waitFor(() -> STRING_TEST.equals(filter.getResult()));
}
}
@Test
public void testPerformCompletionWithDPad() throws Throwable {
if (isTvMode()) {
return;
}
final AdapterView.OnItemClickListener mockItemClickListener =
mock(AdapterView.OnItemClickListener.class);
assertFalse(mAutoCompleteTextView.isPerformingCompletion());
mActivityRule.runOnUiThread(() -> {
mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
mAutoCompleteTextView.setAdapter(mAdapter);
mAutoCompleteTextView.requestFocus();
mAutoCompleteTextView.showDropDown();
});
mInstrumentation.waitForIdleSync();
assertFalse(mAutoCompleteTextView.isPerformingCompletion());
// Key is ENTER or DPAD_ENTER, will invoke completion
mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_ENTER);
mInstrumentation.waitForIdleSync();
verify(mockItemClickListener, times(1)).onItemClick(any(AdapterView.class), any(View.class),
eq(0), eq(0L));
assertEquals(WORDS[0], mAutoCompleteTextView.getText().toString());
mActivityRule.runOnUiThread(mAutoCompleteTextView::showDropDown);
mInstrumentation.waitForIdleSync();
mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
verify(mockItemClickListener, times(2)).onItemClick(any(AdapterView.class), any(View.class),
eq(0), eq(0L));
assertEquals(WORDS[0], mAutoCompleteTextView.getText().toString());
assertFalse(mAutoCompleteTextView.isPerformingCompletion());
mActivityRule.runOnUiThread(mAutoCompleteTextView::showDropDown);
mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
// Test normal key code.
mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_0);
verifyNoMoreInteractions(mockItemClickListener);
assertNotSame("", mAutoCompleteTextView.getText().toString());
assertFalse(mAutoCompleteTextView.isPerformingCompletion());
// Test the method on the scene of popup is closed.
mActivityRule.runOnUiThread(mAutoCompleteTextView::dismissDropDown);
mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_ENTER);
verifyNoMoreInteractions(mockItemClickListener);
assertNotSame("", mAutoCompleteTextView.getText().toString());
assertFalse(mAutoCompleteTextView.isPerformingCompletion());
}
@Test
public void testPerformCompletionExplicit() throws Throwable {
final AdapterView.OnItemClickListener mockItemClickListener =
mock(AdapterView.OnItemClickListener.class);
assertFalse(mAutoCompleteTextView.isPerformingCompletion());
// Create a custom watcher that checks isPerformingCompletion to return true
// in the "middle" of the performCompletion processing. We also spy on this watcher
// to make sure that its onTextChanged is invoked.
final TextWatcher myTextWatcher = new MyTextWatcher(WORDS[1]);
final TextWatcher spyTextWatcher = spy(myTextWatcher);
mAutoCompleteTextView.addTextChangedListener(spyTextWatcher);
mActivityRule.runOnUiThread(() -> {
mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
mAutoCompleteTextView.setAdapter(mAdapter);
mAutoCompleteTextView.requestFocus();
mAutoCompleteTextView.showDropDown();
});
mInstrumentation.waitForIdleSync();
assertTrue(mAutoCompleteTextView.isPopupShowing());
assertFalse(mAutoCompleteTextView.isPerformingCompletion());
mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
mActivityRule.runOnUiThread(mAutoCompleteTextView::performCompletion);
verify(mockItemClickListener, times(1)).onItemClick(any(AdapterView.class), any(View.class),
eq(1), eq(1L));
assertEquals(WORDS[1], mAutoCompleteTextView.getText().toString());
assertFalse(mAutoCompleteTextView.isPerformingCompletion());
assertFalse(mAutoCompleteTextView.isPopupShowing());
verify(spyTextWatcher, atLeastOnce()).onTextChanged(sameCharSequence(WORDS[1]),
eq(0), eq(0), eq(WORDS[1].length()));
verifyNoMoreInteractions(mockItemClickListener);
}
@Test
public void testSetTextWithCompletion() throws Throwable {
final AdapterView.OnItemClickListener mockItemClickListener =
mock(AdapterView.OnItemClickListener.class);
mActivityRule.runOnUiThread(() -> {
mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
mAutoCompleteTextView.setAdapter(mAdapter);
});
mInstrumentation.waitForIdleSync();
assertFalse(mAutoCompleteTextView.isPopupShowing());
mActivityRule.runOnUiThread(() -> mAutoCompleteTextView.setText("testO", true));
mInstrumentation.waitForIdleSync();
assertTrue(mAutoCompleteTextView.isPopupShowing());
verifyZeroInteractions(mockItemClickListener);
}
@Test
public void testSetTextWithNoCompletion() throws Throwable {
final AdapterView.OnItemClickListener mockItemClickListener =
mock(AdapterView.OnItemClickListener.class);
mActivityRule.runOnUiThread(() -> {
mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
mAutoCompleteTextView.setAdapter(mAdapter);
});
mInstrumentation.waitForIdleSync();
assertFalse(mAutoCompleteTextView.isPopupShowing());
mActivityRule.runOnUiThread(() -> mAutoCompleteTextView.setText("testO", false));
mInstrumentation.waitForIdleSync();
assertFalse(mAutoCompleteTextView.isPopupShowing());
verifyZeroInteractions(mockItemClickListener);
}
@UiThreadTest
@Test
public void testPerformValidation() {
final CharSequence text = "this";
mAutoCompleteTextView.setValidator(mValidator);
mAutoCompleteTextView.setAdapter((ArrayAdapter<String>) null);
mAutoCompleteTextView.setText(text);
mAutoCompleteTextView.performValidation();
assertEquals(STRING_VALIDATED, mAutoCompleteTextView.getText().toString());
mAutoCompleteTextView.setValidator(null);
}
@UiThreadTest
@Test
public void testAccessCompletionHint() {
mAutoCompleteTextView.setCompletionHint("TEST HINT");
assertEquals("TEST HINT", mAutoCompleteTextView.getCompletionHint());
mAutoCompleteTextView.setCompletionHint(null);
assertNull(mAutoCompleteTextView.getCompletionHint());
}
@Test
public void testAccessListSelection() throws Throwable {
final AdapterView.OnItemClickListener mockItemClickListener =
mock(AdapterView.OnItemClickListener.class);
mActivityRule.runOnUiThread(() -> {
mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
mAutoCompleteTextView.setAdapter(mAdapter);
mAutoCompleteTextView.requestFocus();
mAutoCompleteTextView.showDropDown();
});
mInstrumentation.waitForIdleSync();
mActivityRule.runOnUiThread(() -> {
mAutoCompleteTextView.setListSelection(1);
assertEquals(1, mAutoCompleteTextView.getListSelection());
mAutoCompleteTextView.setListSelection(2);
assertEquals(2, mAutoCompleteTextView.getListSelection());
mAutoCompleteTextView.clearListSelection();
assertEquals(2, mAutoCompleteTextView.getListSelection());
});
mInstrumentation.waitForIdleSync();
}
@UiThreadTest
@Test
public void testAccessDropDownAnchor() {
mAutoCompleteTextView.setDropDownAnchor(View.NO_ID);
assertEquals(View.NO_ID, mAutoCompleteTextView.getDropDownAnchor());
mAutoCompleteTextView.setDropDownAnchor(0x5555);
assertEquals(0x5555, mAutoCompleteTextView.getDropDownAnchor());
}
@UiThreadTest
@Test
public void testAccessDropDownWidth() {
mAutoCompleteTextView.setDropDownWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, mAutoCompleteTextView.getDropDownWidth());
mAutoCompleteTextView.setDropDownWidth(ViewGroup.LayoutParams.MATCH_PARENT);
assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, mAutoCompleteTextView.getDropDownWidth());
}
private class MockValidator implements AutoCompleteTextView.Validator {
public CharSequence fixText(CharSequence invalidText) {
return STRING_VALIDATED;
}
public boolean isValid(CharSequence text) {
return (text == STRING_TEST);
}
}
public static class MockAutoCompleteTextView extends AutoCompleteTextView {
public MockAutoCompleteTextView(Context context) {
super(context);
}
public MockAutoCompleteTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected CharSequence convertSelectionToString(Object selectedItem) {
return super.convertSelectionToString(selectedItem);
}
@Override
protected Filter getFilter() {
return super.getFilter();
}
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(focused, direction, previouslyFocusedRect);
}
@Override
protected void performFiltering(CharSequence text, int keyCode) {
super.performFiltering(text, keyCode);
}
@Override
protected void replaceText(CharSequence text) {
super.replaceText(text);
}
@Override
protected boolean setFrame(int l, int t, int r, int b) {
return super.setFrame(l, t, r, b);
}
}
private static class MockFilter extends Filter {
private String mFilterResult;
@Override
protected FilterResults performFiltering(CharSequence constraint) {
if (constraint != null) {
mFilterResult = constraint.toString();
}
return null;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
}
public String getResult() {
return mFilterResult;
}
}
private static class MockAdapter<T> extends ArrayAdapter<T> implements Filterable {
private MockFilter mFilter;
public MockAdapter(Context context, int textViewResourceId, T[] objects) {
super(context, textViewResourceId, objects);
}
@Override
public Filter getFilter() {
if (mFilter == null) {
mFilter = new MockFilter();
}
return mFilter;
}
}
}