/* * Copyright (C) 2015 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; import static android.support.test.espresso.Espresso.onView; import static android.support.test.espresso.Espresso.pressBack; import static android.support.test.espresso.action.ViewActions.clearText; import static android.support.test.espresso.action.ViewActions.click; import static android.support.test.espresso.action.ViewActions.replaceText; import static android.support.test.espresso.assertion.ViewAssertions.matches; import static android.support.test.espresso.matcher.RootMatchers.withDecorView; import static android.support.test.espresso.matcher.ViewMatchers.withId; import static android.support.test.espresso.matcher.ViewMatchers.withText; import static android.widget.espresso.DragHandleUtils.onHandleView; import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarContainsItem; import static android.widget.espresso.FloatingToolbarEspressoUtils.clickFloatingToolbarItem; import static android.widget.espresso.FloatingToolbarEspressoUtils.sleepForFloatingToolbarPopup; import static android.widget.espresso.SuggestionsPopupwindowUtils.assertSuggestionsPopupContainsItem; import static android.widget.espresso.SuggestionsPopupwindowUtils.assertSuggestionsPopupIsDisplayed; import static android.widget.espresso.SuggestionsPopupwindowUtils.assertSuggestionsPopupIsNotDisplayed; import static android.widget.espresso.SuggestionsPopupwindowUtils.clickSuggestionsPopupItem; import static android.widget.espresso.SuggestionsPopupwindowUtils.onSuggestionsPopup; import static android.widget.espresso.TextViewActions.clickOnTextAtIndex; import static android.widget.espresso.TextViewActions.longPressOnTextAtIndex; import static org.hamcrest.Matchers.is; import android.content.res.TypedArray; import android.support.test.espresso.NoMatchingViewException; import android.support.test.espresso.ViewAssertion; import android.test.ActivityInstrumentationTestCase2; import android.test.suitebuilder.annotation.SmallTest; import android.test.suitebuilder.annotation.Suppress; import android.text.Selection; import android.text.Spannable; import android.text.Spanned; import android.text.TextPaint; import android.text.style.SuggestionSpan; import android.text.style.TextAppearanceSpan; import android.view.View; import com.android.frameworks.coretests.R; /** * SuggestionsPopupWindowTest tests. * * TODO: Add tests for when there are no suggestions */ public class SuggestionsPopupWindowTest extends ActivityInstrumentationTestCase2<TextViewActivity> { public SuggestionsPopupWindowTest() { super(TextViewActivity.class); } @Override protected void setUp() throws Exception { super.setUp(); getActivity(); } private void setSuggestionSpan(SuggestionSpan span, int start, int end) { final TextView textView = (TextView) getActivity().findViewById(R.id.textview); textView.post( () -> { final Spannable text = (Spannable) textView.getText(); text.setSpan(span, start, end, Spanned.SPAN_INCLUSIVE_INCLUSIVE); Selection.setSelection(text, (start + end) / 2); }); getInstrumentation().waitForIdleSync(); } @SmallTest public void testOnTextContextMenuItem() { final String text = "abc def ghi"; onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(replaceText(text)); final SuggestionSpan suggestionSpan = new SuggestionSpan(getActivity(), new String[]{"DEF", "Def"}, SuggestionSpan.FLAG_AUTO_CORRECTION); setSuggestionSpan(suggestionSpan, text.indexOf('d'), text.indexOf('f') + 1); final TextView textView = (TextView) getActivity().findViewById(R.id.textview); textView.post(() -> textView.onTextContextMenuItem(TextView.ID_REPLACE)); getInstrumentation().waitForIdleSync(); assertSuggestionsPopupIsDisplayed(); } @SmallTest public void testSelectionActionMode() { final String text = "abc def ghi"; onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(replaceText(text)); final SuggestionSpan suggestionSpan = new SuggestionSpan(getActivity(), new String[]{"DEF", "Def"}, SuggestionSpan.FLAG_AUTO_CORRECTION); setSuggestionSpan(suggestionSpan, text.indexOf('d'), text.indexOf('f') + 1); onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('e'))); sleepForFloatingToolbarPopup(); assertFloatingToolbarContainsItem( getActivity().getString(com.android.internal.R.string.replace)); sleepForFloatingToolbarPopup(); clickFloatingToolbarItem( getActivity().getString(com.android.internal.R.string.replace)); assertSuggestionsPopupIsDisplayed(); } @SmallTest public void testInsertionActionMode() { final String text = "abc def ghi"; onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(replaceText(text)); final SuggestionSpan suggestionSpan = new SuggestionSpan(getActivity(), new String[]{"DEF", "Def"}, SuggestionSpan.FLAG_AUTO_CORRECTION); setSuggestionSpan(suggestionSpan, text.indexOf('d'), text.indexOf('f') + 1); onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.indexOf('e'))); onHandleView(com.android.internal.R.id.insertion_handle).perform(click()); sleepForFloatingToolbarPopup(); assertFloatingToolbarContainsItem( getActivity().getString(com.android.internal.R.string.replace)); clickFloatingToolbarItem( getActivity().getString(com.android.internal.R.string.replace)); assertSuggestionsPopupIsDisplayed(); } private void showSuggestionsPopup() { final TextView textView = (TextView) getActivity().findViewById(R.id.textview); textView.post(() -> textView.onTextContextMenuItem(TextView.ID_REPLACE)); getInstrumentation().waitForIdleSync(); assertSuggestionsPopupIsDisplayed(); } @SmallTest public void testSuggestionItems() { final String text = "abc def ghi"; onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(replaceText(text)); final SuggestionSpan suggestionSpan = new SuggestionSpan(getActivity(), new String[]{"DEF", "Def"}, SuggestionSpan.FLAG_AUTO_CORRECTION); setSuggestionSpan(suggestionSpan, text.indexOf('d'), text.indexOf('f') + 1); showSuggestionsPopup(); assertSuggestionsPopupIsDisplayed(); assertSuggestionsPopupContainsItem("DEF"); assertSuggestionsPopupContainsItem("Def"); assertSuggestionsPopupContainsItem( getActivity().getString(com.android.internal.R.string.delete)); // Select an item. clickSuggestionsPopupItem("DEF"); assertSuggestionsPopupIsNotDisplayed(); onView(withId(R.id.textview)).check(matches(withText("abc DEF ghi"))); showSuggestionsPopup(); assertSuggestionsPopupIsDisplayed(); assertSuggestionsPopupContainsItem("def"); assertSuggestionsPopupContainsItem("Def"); assertSuggestionsPopupContainsItem( getActivity().getString(com.android.internal.R.string.delete)); // Delete clickSuggestionsPopupItem( getActivity().getString(com.android.internal.R.string.delete)); assertSuggestionsPopupIsNotDisplayed(); onView(withId(R.id.textview)).check(matches(withText("abc ghi"))); } @SmallTest public void testMisspelled() { final String text = "abc def ghi"; onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(replaceText(text)); final SuggestionSpan suggestionSpan = new SuggestionSpan(getActivity(), new String[]{"DEF", "Def"}, SuggestionSpan.FLAG_MISSPELLED); setSuggestionSpan(suggestionSpan, text.indexOf('d'), text.indexOf('f') + 1); showSuggestionsPopup(); assertSuggestionsPopupIsDisplayed(); assertSuggestionsPopupContainsItem("DEF"); assertSuggestionsPopupContainsItem("Def"); assertSuggestionsPopupContainsItem( getActivity().getString(com.android.internal.R.string.addToDictionary)); assertSuggestionsPopupContainsItem( getActivity().getString(com.android.internal.R.string.delete)); // Click "Add to dictionary". clickSuggestionsPopupItem( getActivity().getString(com.android.internal.R.string.addToDictionary)); // TODO: Check if add to dictionary dialog is displayed. } @SmallTest public void testEasyCorrect() { final String text = "abc def ghi"; onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(replaceText(text)); final SuggestionSpan suggestionSpan = new SuggestionSpan(getActivity(), new String[]{"DEF", "Def"}, SuggestionSpan.FLAG_EASY_CORRECT | SuggestionSpan.FLAG_MISSPELLED); setSuggestionSpan(suggestionSpan, text.indexOf('d'), text.indexOf('f') + 1); onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.indexOf('e'))); assertSuggestionsPopupIsDisplayed(); assertSuggestionsPopupContainsItem("DEF"); assertSuggestionsPopupContainsItem("Def"); assertSuggestionsPopupContainsItem( getActivity().getString(com.android.internal.R.string.delete)); // Select an item. clickSuggestionsPopupItem("DEF"); assertSuggestionsPopupIsNotDisplayed(); onView(withId(R.id.textview)).check(matches(withText("abc DEF ghi"))); onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.indexOf('e'))); assertSuggestionsPopupIsNotDisplayed(); showSuggestionsPopup(); assertSuggestionsPopupIsDisplayed(); assertSuggestionsPopupContainsItem("def"); assertSuggestionsPopupContainsItem("Def"); assertSuggestionsPopupContainsItem( getActivity().getString(com.android.internal.R.string.delete)); } @SmallTest public void testTextAppearanceInSuggestionsPopup() { final String text = "abc def ghi"; final String[] singleWordCandidates = {"DEF", "Def"}; final SuggestionSpan suggestionSpan = new SuggestionSpan(getActivity(), singleWordCandidates, SuggestionSpan.FLAG_MISSPELLED); final String[] multiWordCandidates = {"ABC DEF GHI", "Abc Def Ghi"}; final SuggestionSpan multiWordSuggestionSpan = new SuggestionSpan(getActivity(), multiWordCandidates, SuggestionSpan.FLAG_MISSPELLED); final TypedArray array = getActivity().obtainStyledAttributes(com.android.internal.R.styleable.Theme); final int id = array.getResourceId( com.android.internal.R.styleable.Theme_textEditSuggestionHighlightStyle, 0); array.recycle(); final TextAppearanceSpan expectedSpan = new TextAppearanceSpan(getActivity(), id); final TextPaint tmpTp = new TextPaint(); expectedSpan.updateDrawState(tmpTp); final int expectedHighlightTextColor = tmpTp.getColor(); final float expectedHighlightTextSize = tmpTp.getTextSize(); final TextView textView = (TextView) getActivity().findViewById(R.id.textview); // In this test, the SuggestionsPopupWindow looks like // abc def ghi // ----------------- // | abc *DEF* ghi | // | abc *Def* ghi | // | *ABC DEF GHI* | // | *Abc Def Ghi* | // ----------------- // | DELETE | // ----------------- // *XX* means that XX is highlighted. for (int i = 0; i < 2; i++) { onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(replaceText(text)); setSuggestionSpan(suggestionSpan, text.indexOf('d'), text.indexOf('f') + 1); setSuggestionSpan(multiWordSuggestionSpan, 0, text.length()); showSuggestionsPopup(); assertSuggestionsPopupIsDisplayed(); assertSuggestionsPopupContainsItem("abc DEF ghi"); assertSuggestionsPopupContainsItem("abc Def ghi"); assertSuggestionsPopupContainsItem("ABC DEF GHI"); assertSuggestionsPopupContainsItem("Abc Def Ghi"); assertSuggestionsPopupContainsItem( getActivity().getString(com.android.internal.R.string.delete)); onSuggestionsPopup().check(new ViewAssertion() { @Override public void check(View view, NoMatchingViewException e) { final ListView listView = (ListView) view.findViewById( com.android.internal.R.id.suggestionContainer); assertNotNull(listView); final int childNum = listView.getChildCount(); assertEquals(singleWordCandidates.length + multiWordCandidates.length, childNum); for (int j = 0; j < childNum; j++) { final TextView suggestion = (TextView) listView.getChildAt(j); assertNotNull(suggestion); final Spanned spanned = (Spanned) suggestion.getText(); assertNotNull(spanned); // Check that the suggestion item order is kept. final String expectedText; if (j < singleWordCandidates.length) { expectedText = "abc " + singleWordCandidates[j] + " ghi"; } else { expectedText = multiWordCandidates[j - singleWordCandidates.length]; } assertEquals(expectedText, spanned.toString()); // Check that the text is highlighted with correct color and text size. final TextAppearanceSpan[] taSpan = spanned.getSpans( text.indexOf('d'), text.indexOf('f') + 1, TextAppearanceSpan.class); assertEquals(1, taSpan.length); TextPaint tp = new TextPaint(); taSpan[0].updateDrawState(tp); assertEquals(expectedHighlightTextColor, tp.getColor()); assertEquals(expectedHighlightTextSize, tp.getTextSize()); // Check the correct part of the text is highlighted. final int expectedStart; final int expectedEnd; if (j < singleWordCandidates.length) { expectedStart = text.indexOf('d'); expectedEnd = text.indexOf('f') + 1; } else { expectedStart = 0; expectedEnd = text.length(); } assertEquals(expectedStart, spanned.getSpanStart(taSpan[0])); assertEquals(expectedEnd, spanned.getSpanEnd(taSpan[0])); } } }); pressBack(); onView(withId(R.id.textview)) .inRoot(withDecorView(is(getActivity().getWindow().getDecorView()))) .perform(clearText()); } } }