RichInputConnectionAndTextRangeTests.java revision bb843eb223ce0f8fb1088ed3393a4165123ddb1f
1/* 2 * Copyright (C) 2012 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 17package com.android.inputmethod.latin; 18 19import android.content.res.Resources; 20import android.inputmethodservice.InputMethodService; 21import android.os.Parcel; 22import android.test.AndroidTestCase; 23import android.test.MoreAsserts; 24import android.test.suitebuilder.annotation.SmallTest; 25import android.text.SpannableString; 26import android.text.TextUtils; 27import android.text.style.SuggestionSpan; 28import android.view.inputmethod.ExtractedText; 29import android.view.inputmethod.ExtractedTextRequest; 30import android.view.inputmethod.InputConnection; 31import android.view.inputmethod.InputConnectionWrapper; 32 33import com.android.inputmethod.latin.PrevWordsInfo.WordInfo; 34import com.android.inputmethod.latin.settings.SpacingAndPunctuations; 35import com.android.inputmethod.latin.utils.PrevWordsInfoUtils; 36import com.android.inputmethod.latin.utils.RunInLocale; 37import com.android.inputmethod.latin.utils.ScriptUtils; 38import com.android.inputmethod.latin.utils.StringUtils; 39import com.android.inputmethod.latin.utils.TextRange; 40 41import java.util.Locale; 42 43@SmallTest 44public class RichInputConnectionAndTextRangeTests extends AndroidTestCase { 45 46 // The following is meant to be a reasonable default for 47 // the "word_separators" resource. 48 private SpacingAndPunctuations mSpacingAndPunctuations; 49 50 @Override 51 protected void setUp() throws Exception { 52 super.setUp(); 53 final RunInLocale<SpacingAndPunctuations> job = new RunInLocale<SpacingAndPunctuations>() { 54 @Override 55 protected SpacingAndPunctuations job(final Resources res) { 56 return new SpacingAndPunctuations(res); 57 } 58 }; 59 final Resources res = getContext().getResources(); 60 mSpacingAndPunctuations = job.runInLocale(res, Locale.ENGLISH); 61 } 62 63 private class MockConnection extends InputConnectionWrapper { 64 final CharSequence mTextBefore; 65 final CharSequence mTextAfter; 66 final ExtractedText mExtractedText; 67 68 public MockConnection(final CharSequence text, final int cursorPosition) { 69 super(null, false); 70 // Interaction of spans with Parcels is completely non-trivial, but in the actual case 71 // the CharSequences do go through Parcels because they go through IPC. There 72 // are some significant differences between the behavior of Spanned objects that 73 // have and that have not gone through parceling, so it's much easier to simulate 74 // the environment with Parcels than try to emulate things by hand. 75 final Parcel p = Parcel.obtain(); 76 TextUtils.writeToParcel(text.subSequence(0, cursorPosition), p, 0 /* flags */); 77 TextUtils.writeToParcel(text.subSequence(cursorPosition, text.length()), p, 78 0 /* flags */); 79 final byte[] marshalled = p.marshall(); 80 p.unmarshall(marshalled, 0, marshalled.length); 81 p.setDataPosition(0); 82 mTextBefore = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p); 83 mTextAfter = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p); 84 mExtractedText = null; 85 p.recycle(); 86 } 87 88 public MockConnection(String textBefore, String textAfter, ExtractedText extractedText) { 89 super(null, false); 90 mTextBefore = textBefore; 91 mTextAfter = textAfter; 92 mExtractedText = extractedText; 93 } 94 95 public int cursorPos() { 96 return mTextBefore.length(); 97 } 98 99 /* (non-Javadoc) 100 * @see android.view.inputmethod.InputConnectionWrapper#getTextBeforeCursor(int, int) 101 */ 102 @Override 103 public CharSequence getTextBeforeCursor(int n, int flags) { 104 return mTextBefore; 105 } 106 107 /* (non-Javadoc) 108 * @see android.view.inputmethod.InputConnectionWrapper#getTextAfterCursor(int, int) 109 */ 110 @Override 111 public CharSequence getTextAfterCursor(int n, int flags) { 112 return mTextAfter; 113 } 114 115 /* (non-Javadoc) 116 * @see android.view.inputmethod.InputConnectionWrapper#getExtractedText( 117 * ExtractedTextRequest, int) 118 */ 119 @Override 120 public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) { 121 return mExtractedText; 122 } 123 124 @Override 125 public boolean beginBatchEdit() { 126 return true; 127 } 128 129 @Override 130 public boolean endBatchEdit() { 131 return true; 132 } 133 134 @Override 135 public boolean finishComposingText() { 136 return true; 137 } 138 } 139 140 private class MockInputMethodService extends InputMethodService { 141 private MockConnection mMockConnection; 142 public void setInputConnection(final MockConnection mockConnection) { 143 mMockConnection = mockConnection; 144 } 145 public int cursorPos() { 146 return mMockConnection.cursorPos(); 147 } 148 @Override 149 public InputConnection getCurrentInputConnection() { 150 return mMockConnection; 151 } 152 } 153 154 /************************** Tests ************************/ 155 156 /** 157 * Test for getting previous word (for bigram suggestions) 158 */ 159 public void testGetPreviousWord() { 160 // If one of the following cases breaks, the bigram suggestions won't work. 161 assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord( 162 "abc def", mSpacingAndPunctuations, 2).mPrevWordsInfo[0].mWord, "abc"); 163 assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord( 164 "abc", mSpacingAndPunctuations, 2), PrevWordsInfo.BEGINNING_OF_SENTENCE); 165 assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord( 166 "abc. def", mSpacingAndPunctuations, 2), PrevWordsInfo.BEGINNING_OF_SENTENCE); 167 168 assertFalse(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord( 169 "abc def", mSpacingAndPunctuations, 2).mPrevWordsInfo[0].mIsBeginningOfSentence); 170 assertTrue(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord( 171 "abc", mSpacingAndPunctuations, 2).mPrevWordsInfo[0].mIsBeginningOfSentence); 172 173 // For n-gram 174 assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord( 175 "abc def", mSpacingAndPunctuations, 1).mPrevWordsInfo[0].mWord, "def"); 176 assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord( 177 "abc def", mSpacingAndPunctuations, 1).mPrevWordsInfo[1].mWord, "abc"); 178 assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord( 179 "abc def", mSpacingAndPunctuations, 2).mPrevWordsInfo[1], 180 WordInfo.BEGINNING_OF_SENTENCE); 181 182 // The following tests reflect the current behavior of the function 183 // RichInputConnection#getNthPreviousWord. 184 // TODO: However at this time, the code does never go 185 // into such a path, so it should be safe to change the behavior of 186 // this function if needed - especially since it does not seem very 187 // logical. These tests are just there to catch any unintentional 188 // changes in the behavior of the RichInputConnection#getPreviousWord method. 189 assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord( 190 "abc def ", mSpacingAndPunctuations, 2).mPrevWordsInfo[0].mWord, "abc"); 191 assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord( 192 "abc def.", mSpacingAndPunctuations, 2).mPrevWordsInfo[0].mWord, "abc"); 193 assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord( 194 "abc def .", mSpacingAndPunctuations, 2).mPrevWordsInfo[0].mWord, "def"); 195 assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord( 196 "abc ", mSpacingAndPunctuations, 2), PrevWordsInfo.BEGINNING_OF_SENTENCE); 197 198 assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord( 199 "abc def", mSpacingAndPunctuations, 1).mPrevWordsInfo[0].mWord, "def"); 200 assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord( 201 "abc def ", mSpacingAndPunctuations, 1).mPrevWordsInfo[0].mWord, "def"); 202 assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord( 203 "abc 'def", mSpacingAndPunctuations, 1).mPrevWordsInfo[0].mWord, "'def"); 204 assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord( 205 "abc def.", mSpacingAndPunctuations, 1), PrevWordsInfo.BEGINNING_OF_SENTENCE); 206 assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord( 207 "abc def .", mSpacingAndPunctuations, 1), PrevWordsInfo.BEGINNING_OF_SENTENCE); 208 assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord( 209 "abc, def", mSpacingAndPunctuations, 2), PrevWordsInfo.EMPTY_PREV_WORDS_INFO); 210 assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord( 211 "abc? def", mSpacingAndPunctuations, 2), PrevWordsInfo.EMPTY_PREV_WORDS_INFO); 212 assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord( 213 "abc! def", mSpacingAndPunctuations, 2), PrevWordsInfo.EMPTY_PREV_WORDS_INFO); 214 assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord( 215 "abc 'def", mSpacingAndPunctuations, 2), PrevWordsInfo.EMPTY_PREV_WORDS_INFO); 216 } 217 218 /** 219 * Test logic in getting the word range at the cursor. 220 */ 221 private static final int[] SPACE = { Constants.CODE_SPACE }; 222 static final int[] TAB = { Constants.CODE_TAB }; 223 private static final int[] SPACE_TAB = StringUtils.toSortedCodePointArray(" \t"); 224 // A character that needs surrogate pair to represent its code point (U+2008A). 225 private static final String SUPPLEMENTARY_CHAR = "\uD840\uDC8A"; 226 private static final String HIRAGANA_WORD = "\u3042\u3044\u3046\u3048\u304A"; // あいうえお 227 private static final String GREEK_WORD = "\u03BA\u03B1\u03B9"; // και 228 229 public void testGetWordRangeAtCursor() { 230 ExtractedText et = new ExtractedText(); 231 final MockInputMethodService mockInputMethodService = new MockInputMethodService(); 232 final RichInputConnection ic = new RichInputConnection(mockInputMethodService); 233 mockInputMethodService.setInputConnection(new MockConnection("word wo", "rd", et)); 234 et.startOffset = 0; 235 et.selectionStart = 7; 236 TextRange r; 237 238 ic.beginBatchEdit(); 239 // basic case 240 r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN); 241 assertTrue(TextUtils.equals("word", r.mWord)); 242 243 // tab character instead of space 244 mockInputMethodService.setInputConnection(new MockConnection("one\tword\two", "rd", et)); 245 ic.beginBatchEdit(); 246 r = ic.getWordRangeAtCursor(TAB, ScriptUtils.SCRIPT_LATIN); 247 ic.endBatchEdit(); 248 assertTrue(TextUtils.equals("word", r.mWord)); 249 250 // splitting on supplementary character 251 mockInputMethodService.setInputConnection( 252 new MockConnection("one word" + SUPPLEMENTARY_CHAR + "wo", "rd", et)); 253 ic.beginBatchEdit(); 254 r = ic.getWordRangeAtCursor(StringUtils.toSortedCodePointArray(SUPPLEMENTARY_CHAR), 255 ScriptUtils.SCRIPT_LATIN); 256 ic.endBatchEdit(); 257 assertTrue(TextUtils.equals("word", r.mWord)); 258 259 // split on chars outside the specified script 260 mockInputMethodService.setInputConnection( 261 new MockConnection(HIRAGANA_WORD + "wo", "rd" + GREEK_WORD, et)); 262 ic.beginBatchEdit(); 263 r = ic.getWordRangeAtCursor(StringUtils.toSortedCodePointArray(SUPPLEMENTARY_CHAR), 264 ScriptUtils.SCRIPT_LATIN); 265 ic.endBatchEdit(); 266 assertTrue(TextUtils.equals("word", r.mWord)); 267 268 // likewise for greek 269 mockInputMethodService.setInputConnection( 270 new MockConnection("text" + GREEK_WORD, "text", et)); 271 ic.beginBatchEdit(); 272 r = ic.getWordRangeAtCursor(StringUtils.toSortedCodePointArray(SUPPLEMENTARY_CHAR), 273 ScriptUtils.SCRIPT_GREEK); 274 ic.endBatchEdit(); 275 assertTrue(TextUtils.equals(GREEK_WORD, r.mWord)); 276 } 277 278 /** 279 * Test logic in getting the word range at the cursor. 280 */ 281 public void testGetSuggestionSpansAtWord() { 282 helpTestGetSuggestionSpansAtWord(10); 283 helpTestGetSuggestionSpansAtWord(12); 284 helpTestGetSuggestionSpansAtWord(15); 285 helpTestGetSuggestionSpansAtWord(16); 286 } 287 288 private void helpTestGetSuggestionSpansAtWord(final int cursorPos) { 289 final MockInputMethodService mockInputMethodService = new MockInputMethodService(); 290 final RichInputConnection ic = new RichInputConnection(mockInputMethodService); 291 292 final String[] SUGGESTIONS1 = { "swing", "strong" }; 293 final String[] SUGGESTIONS2 = { "storing", "strung" }; 294 295 // Test the usual case. 296 SpannableString text = new SpannableString("This is a string for test"); 297 text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */), 298 10 /* start */, 16 /* end */, 0 /* flags */); 299 mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos)); 300 TextRange r; 301 SuggestionSpan[] suggestions; 302 303 r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN); 304 suggestions = r.getSuggestionSpansAtWord(); 305 assertEquals(suggestions.length, 1); 306 MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1); 307 308 // Test the case with 2 suggestion spans in the same place. 309 text = new SpannableString("This is a string for test"); 310 text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */), 311 10 /* start */, 16 /* end */, 0 /* flags */); 312 text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */), 313 10 /* start */, 16 /* end */, 0 /* flags */); 314 mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos)); 315 r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN); 316 suggestions = r.getSuggestionSpansAtWord(); 317 assertEquals(suggestions.length, 2); 318 MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1); 319 MoreAsserts.assertEquals(suggestions[1].getSuggestions(), SUGGESTIONS2); 320 321 // Test a case with overlapping spans, 2nd extending past the start of the word 322 text = new SpannableString("This is a string for test"); 323 text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */), 324 10 /* start */, 16 /* end */, 0 /* flags */); 325 text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */), 326 5 /* start */, 16 /* end */, 0 /* flags */); 327 mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos)); 328 r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN); 329 suggestions = r.getSuggestionSpansAtWord(); 330 assertEquals(suggestions.length, 1); 331 MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1); 332 333 // Test a case with overlapping spans, 2nd extending past the end of the word 334 text = new SpannableString("This is a string for test"); 335 text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */), 336 10 /* start */, 16 /* end */, 0 /* flags */); 337 text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */), 338 10 /* start */, 20 /* end */, 0 /* flags */); 339 mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos)); 340 r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN); 341 suggestions = r.getSuggestionSpansAtWord(); 342 assertEquals(suggestions.length, 1); 343 MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1); 344 345 // Test a case with overlapping spans, 2nd extending past both ends of the word 346 text = new SpannableString("This is a string for test"); 347 text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */), 348 10 /* start */, 16 /* end */, 0 /* flags */); 349 text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */), 350 5 /* start */, 20 /* end */, 0 /* flags */); 351 mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos)); 352 r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN); 353 suggestions = r.getSuggestionSpansAtWord(); 354 assertEquals(suggestions.length, 1); 355 MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1); 356 357 // Test a case with overlapping spans, none right on the word 358 text = new SpannableString("This is a string for test"); 359 text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */), 360 5 /* start */, 16 /* end */, 0 /* flags */); 361 text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */), 362 5 /* start */, 20 /* end */, 0 /* flags */); 363 mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos)); 364 r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN); 365 suggestions = r.getSuggestionSpansAtWord(); 366 assertEquals(suggestions.length, 0); 367 } 368 369 public void testCursorTouchingWord() { 370 final MockInputMethodService ims = new MockInputMethodService(); 371 final RichInputConnection ic = new RichInputConnection(ims); 372 final SpacingAndPunctuations sap = mSpacingAndPunctuations; 373 374 ims.setInputConnection(new MockConnection("users", 5)); 375 ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); 376 assertTrue(ic.isCursorTouchingWord(sap)); 377 378 ims.setInputConnection(new MockConnection("users'", 5)); 379 ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); 380 assertTrue(ic.isCursorTouchingWord(sap)); 381 382 ims.setInputConnection(new MockConnection("users'", 6)); 383 ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); 384 assertTrue(ic.isCursorTouchingWord(sap)); 385 386 ims.setInputConnection(new MockConnection("'users'", 6)); 387 ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); 388 assertTrue(ic.isCursorTouchingWord(sap)); 389 390 ims.setInputConnection(new MockConnection("'users'", 7)); 391 ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); 392 assertTrue(ic.isCursorTouchingWord(sap)); 393 394 ims.setInputConnection(new MockConnection("users '", 6)); 395 ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); 396 assertFalse(ic.isCursorTouchingWord(sap)); 397 398 ims.setInputConnection(new MockConnection("users '", 7)); 399 ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); 400 assertFalse(ic.isCursorTouchingWord(sap)); 401 402 ims.setInputConnection(new MockConnection("re-", 3)); 403 ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); 404 assertTrue(ic.isCursorTouchingWord(sap)); 405 406 ims.setInputConnection(new MockConnection("re--", 4)); 407 ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); 408 assertFalse(ic.isCursorTouchingWord(sap)); 409 410 ims.setInputConnection(new MockConnection("-", 1)); 411 ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); 412 assertFalse(ic.isCursorTouchingWord(sap)); 413 414 ims.setInputConnection(new MockConnection("--", 2)); 415 ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); 416 assertFalse(ic.isCursorTouchingWord(sap)); 417 418 ims.setInputConnection(new MockConnection(" -", 2)); 419 ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); 420 assertFalse(ic.isCursorTouchingWord(sap)); 421 422 ims.setInputConnection(new MockConnection(" --", 3)); 423 ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); 424 assertFalse(ic.isCursorTouchingWord(sap)); 425 426 ims.setInputConnection(new MockConnection(" users '", 1)); 427 ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); 428 assertTrue(ic.isCursorTouchingWord(sap)); 429 430 ims.setInputConnection(new MockConnection(" users '", 3)); 431 ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); 432 assertTrue(ic.isCursorTouchingWord(sap)); 433 434 ims.setInputConnection(new MockConnection(" users '", 7)); 435 ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); 436 assertFalse(ic.isCursorTouchingWord(sap)); 437 438 ims.setInputConnection(new MockConnection(" users are", 7)); 439 ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); 440 assertTrue(ic.isCursorTouchingWord(sap)); 441 442 ims.setInputConnection(new MockConnection(" users 'are", 7)); 443 ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); 444 assertFalse(ic.isCursorTouchingWord(sap)); 445 } 446} 447