| Index: content/public/android/junit/src/org/chromium/content/browser/input/ThreadedInputConnectionTest.java
|
| diff --git a/content/public/android/junit/src/org/chromium/content/browser/input/ThreadedInputConnectionTest.java b/content/public/android/junit/src/org/chromium/content/browser/input/ThreadedInputConnectionTest.java
|
| index 124e3259f300fd0b7d7993d50870ee54bdd92f72..3bcbb37222bff9aaa5a7178398164eb00cadc172 100644
|
| --- a/content/public/android/junit/src/org/chromium/content/browser/input/ThreadedInputConnectionTest.java
|
| +++ b/content/public/android/junit/src/org/chromium/content/browser/input/ThreadedInputConnectionTest.java
|
| @@ -6,6 +6,7 @@ package org.chromium.content.browser.input;
|
|
|
| import static org.junit.Assert.assertEquals;
|
| import static org.junit.Assert.assertFalse;
|
| +import static org.junit.Assert.assertNotEquals;
|
| import static org.junit.Assert.assertNull;
|
| import static org.junit.Assert.assertTrue;
|
| import static org.junit.Assert.fail;
|
| @@ -32,6 +33,8 @@ import org.mockito.Mockito;
|
| import org.mockito.MockitoAnnotations;
|
| import org.robolectric.annotation.Config;
|
|
|
| +import java.util.concurrent.Callable;
|
| +
|
| /**
|
| * Unit tests for {@ThreadedInputConnection}.
|
| */
|
| @@ -44,6 +47,7 @@ public class ThreadedInputConnectionTest {
|
| InOrder mInOrder;
|
| View mView;
|
| Context mContext;
|
| + boolean mRunningOnUiThread;
|
|
|
| @Before
|
| public void setUp() throws Exception {
|
| @@ -59,7 +63,12 @@ public class ThreadedInputConnectionTest {
|
| when(mContext.getSystemService(Context.INPUT_METHOD_SERVICE)).thenReturn(Mockito.mock(
|
| InputMethodManager.class));
|
| // Let's create Handler for test thread and pretend that it is running on IME thread.
|
| - mConnection = new ThreadedInputConnection(mView, mImeAdapter, new Handler());
|
| + mConnection = new ThreadedInputConnection(mView, mImeAdapter, new Handler()) {
|
| + @Override
|
| + protected boolean runningOnUiThread() {
|
| + return mRunningOnUiThread;
|
| + }
|
| + };
|
| }
|
|
|
| @Test
|
| @@ -70,12 +79,12 @@ public class ThreadedInputConnectionTest {
|
| mInOrder.verify(mImeAdapter).sendCompositionToNative("hello", 1, false, 0);
|
|
|
| // Renderer updates states asynchronously.
|
| - mConnection.updateStateOnUiThread("hello", 5, 5, 0, 5, true, true);
|
| + mConnection.updateStateOnUiThread("hello", 5, 5, 0, 5, true, true, false);
|
| mInOrder.verify(mImeAdapter).updateSelection(5, 5, 0, 5);
|
| assertEquals(0, mConnection.getQueueForTest().size());
|
|
|
| // Prepare to call requestTextInputStateUpdate.
|
| - mConnection.updateStateOnUiThread("hello", 5, 5, 0, 5, true, false);
|
| + mConnection.updateStateOnUiThread("hello", 5, 5, 0, 5, true, false, false);
|
| assertEquals(1, mConnection.getQueueForTest().size());
|
| when(mImeAdapter.requestTextInputStateUpdate()).thenReturn(true);
|
|
|
| @@ -85,11 +94,11 @@ public class ThreadedInputConnectionTest {
|
| // IME app calls finishComposingText().
|
| mConnection.finishComposingText();
|
| mInOrder.verify(mImeAdapter).finishComposingText();
|
| - mConnection.updateStateOnUiThread("hello", 5, 5, -1, -1, true, true);
|
| + mConnection.updateStateOnUiThread("hello", 5, 5, -1, -1, true, true, false);
|
| mInOrder.verify(mImeAdapter).updateSelection(5, 5, -1, -1);
|
|
|
| // Prepare to call requestTextInputStateUpdate.
|
| - mConnection.updateStateOnUiThread("hello", 5, 5, -1, -1, true, false);
|
| + mConnection.updateStateOnUiThread("hello", 5, 5, -1, -1, true, false, false);
|
| assertEquals(1, mConnection.getQueueForTest().size());
|
| when(mImeAdapter.requestTextInputStateUpdate()).thenReturn(true);
|
|
|
| @@ -103,7 +112,7 @@ public class ThreadedInputConnectionTest {
|
| @Feature({"TextInput"})
|
| public void testPressingDeadKey() {
|
| // On default keyboard "Alt+i" produces a dead key '\u0302'.
|
| - mConnection.setCombiningAccent(0x0302);
|
| + mConnection.setCombiningAccentOnUiThread(0x0302);
|
| mConnection.updateComposingText("\u0302", 1, true);
|
| mInOrder.verify(mImeAdapter)
|
| .sendCompositionToNative(
|
| @@ -114,7 +123,7 @@ public class ThreadedInputConnectionTest {
|
| @Feature({"TextInput"})
|
| public void testRenderChangeUpdatesSelection() {
|
| // User moves the cursor.
|
| - mConnection.updateStateOnUiThread("hello", 4, 4, -1, -1, true, true);
|
| + mConnection.updateStateOnUiThread("hello", 4, 4, -1, -1, true, true, false);
|
| mInOrder.verify(mImeAdapter).updateSelection(4, 4, -1, -1);
|
| assertEquals(0, mConnection.getQueueForTest().size());
|
| }
|
| @@ -122,17 +131,34 @@ public class ThreadedInputConnectionTest {
|
| @Test
|
| @Feature({"TextInput"})
|
| public void testBatchEdit() {
|
| + // Type 'hello'.
|
| + assertTrue(mConnection.commitText("hello ", 1));
|
| // IME app calls beginBatchEdit().
|
| assertTrue(mConnection.beginBatchEdit());
|
| - // Type hello real fast.
|
| - mConnection.commitText("hello", 1);
|
| - mInOrder.verify(mImeAdapter).sendCompositionToNative("hello", 1, true, 0);
|
| + // Type 'world'.
|
| + assertTrue(mConnection.commitText("world", 1));
|
| + mInOrder.verify(mImeAdapter).sendCompositionToNative("hello ", 1, true, 0);
|
| + mInOrder.verify(mImeAdapter).beginBatchEdit();
|
| + mInOrder.verify(mImeAdapter).sendCompositionToNative("world", 1, true, 0);
|
|
|
| // Renderer updates states asynchronously.
|
| - mConnection.updateStateOnUiThread("hello", 5, 5, -1, -1, true, true);
|
| - mInOrder.verify(mImeAdapter, never()).updateSelection(5, 5, -1, -1);
|
| + mConnection.updateStateOnUiThread(
|
| + "hello ", 6, 6, -1, -1, true, true, false /* batchEdit */);
|
| + mConnection.updateStateOnUiThread(
|
| + "hello world", 11, 11, -1, -1, true, true, true /* batchEdit */);
|
| + // 'hello ' is called before beginBatchEdit(), so we still need to update it.
|
| + mInOrder.verify(mImeAdapter).updateSelection(6, 6, -1, -1);
|
| + mInOrder.verify(mImeAdapter, never()).updateSelection(11, 11, -1, -1);
|
| assertEquals(0, mConnection.getQueueForTest().size());
|
|
|
| + // Prepare to call getTextBeforeCursor().
|
| + mConnection.updateStateOnUiThread(
|
| + "hello world", 11, 11, -1, -1, true, false /* isNonImeChange */, true);
|
| + when(mImeAdapter.requestTextInputStateUpdate()).thenReturn(true);
|
| +
|
| + assertEquals("hello world", mConnection.getTextBeforeCursor(20, 0));
|
| + mInOrder.verify(mImeAdapter).requestTextInputStateUpdate();
|
| +
|
| {
|
| // Nest another batch edit.
|
| assertTrue(mConnection.beginBatchEdit());
|
| @@ -140,18 +166,47 @@ public class ThreadedInputConnectionTest {
|
| mConnection.setSelection(4, 4);
|
| assertTrue(mConnection.endBatchEdit());
|
| }
|
| + mInOrder.verify(mImeAdapter).setEditableSelectionOffsets(4, 4);
|
| +
|
| + // Renderer updates state for setSelection().
|
| + mConnection.updateStateOnUiThread(
|
| + "hello world", 4, 4, -1, -1, true, true, true /* batchEdit */);
|
| +
|
| // We still have one outer batch edit, so should not update selection yet.
|
| mInOrder.verify(mImeAdapter, never()).updateSelection(4, 4, -1, -1);
|
|
|
| - // Prepare to call requestTextInputStateUpdate.
|
| - mConnection.updateStateOnUiThread("hello", 4, 4, -1, -1, true, false);
|
| - assertEquals(1, mConnection.getQueueForTest().size());
|
| - when(mImeAdapter.requestTextInputStateUpdate()).thenReturn(true);
|
| -
|
| // IME app calls endBatchEdit().
|
| assertFalse(mConnection.endBatchEdit());
|
| // Batch edit is finished, now update selection.
|
| + mConnection.updateStateOnUiThread(
|
| + "hello world", 4, 4, -1, -1, true, true, false /* batchEdit */);
|
| +
|
| + mInOrder.verify(mImeAdapter).endBatchEdit();
|
| mInOrder.verify(mImeAdapter).updateSelection(4, 4, -1, -1);
|
| + mInOrder.verifyNoMoreInteractions();
|
| + assertEquals(0, mConnection.getQueueForTest().size());
|
| + }
|
| +
|
| + @Test
|
| + @Feature({"TextInput"})
|
| + public void testBatchEdit_NoOp() {
|
| + assertTrue(mConnection.beginBatchEdit());
|
| + assertFalse(mConnection.endBatchEdit());
|
| + // This is added just for testing the above.
|
| + assertTrue(mConnection.commitText("hello", 1));
|
| +
|
| + // State update for endBatchEdit.
|
| + mConnection.updateStateOnUiThread(
|
| + "", 0, 0, -1, -1, true, false /* isNonImeChange */, false /* batchEdit */);
|
| + // State update for commitText.
|
| + mConnection.updateStateOnUiThread(
|
| + "hello", 5, 5, -1, -1, true, true, false /* batchEdit */);
|
| + mInOrder.verify(mImeAdapter).beginBatchEdit();
|
| + mInOrder.verify(mImeAdapter).endBatchEdit();
|
| + mInOrder.verify(mImeAdapter).sendCompositionToNative("hello", 1, true, 0);
|
| + mInOrder.verify(mImeAdapter).updateSelection(0, 0, -1, -1);
|
| + mInOrder.verify(mImeAdapter).updateSelection(5, 5, -1, -1);
|
| + mInOrder.verifyNoMoreInteractions();
|
| assertEquals(0, mConnection.getQueueForTest().size());
|
| }
|
|
|
| @@ -186,4 +241,31 @@ public class ThreadedInputConnectionTest {
|
| // Should not hang here. Return null to indicate failure.
|
| assertEquals(null, mConnection.getTextBeforeCursor(10, 0));
|
| }
|
| +
|
| + // crbug.com/643477
|
| + @Test
|
| + @Feature({"TextInput"})
|
| + public void testUiThreadAccess() {
|
| + assertTrue(mConnection.commitText("hello", 1));
|
| + mRunningOnUiThread = true;
|
| + // Depending on the timing, the result may not be up-to-date.
|
| + assertNotEquals("hello",
|
| + ThreadUtils.runOnUiThreadBlockingNoException(new Callable<CharSequence>() {
|
| + @Override
|
| + public CharSequence call() {
|
| + return mConnection.getTextBeforeCursor(10, 0);
|
| + }
|
| + }));
|
| + // Or it could be.
|
| + mConnection.updateStateOnUiThread("hello", 5, 5, -1, -1, true, true, false);
|
| + assertEquals("hello",
|
| + ThreadUtils.runOnUiThreadBlockingNoException(new Callable<CharSequence>() {
|
| + @Override
|
| + public CharSequence call() {
|
| + return mConnection.getTextBeforeCursor(10, 0);
|
| + }
|
| + }));
|
| +
|
| + mRunningOnUiThread = false;
|
| + }
|
| }
|
|
|