Commit bae36d80 authored by changwan's avatar changwan Committed by Commit bot

Prevent real IME from interfering with UrlBarTest

Android framework does not provide an easy way to remove keyboard app
from the testing (unless you use Robolectric).

So far we have been allowing the current keyboard app to interfere with
test and thus flaked test results. Especially, when you make selection
change, Google Latin Keyboard tries to look at the new status by running

beginBatchEdit() -> getTextBeforeCursor() -> endBatchEdit().

And this disrupted batch edit logic such as mInBatchEditMode.

With this change, onCreateInputConnection() will now return null, so
keyboard app cannot interact with the text. Also, dispatchKeyEvent
will ignore key events when it has to.

Note that the test can still interact with BaseInputConnection's method
and thus affects EditText's Editable through UrlBar#getInputConnection().

In doing so, I've guarded KeyUtils#dispatchKeyEventToView() to work with
UI thread.

BUG=723901

Review-Url: https://codereview.chromium.org/2894073002
Cr-Commit-Position: refs/heads/master@{#473782}
parent 43417886
......@@ -12,6 +12,7 @@ import android.text.Selection;
import android.text.Spanned;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
......@@ -53,6 +54,8 @@ public class AutocompleteEditText extends VerticallyFixedEditText {
private boolean mIgnoreTextChangeFromAutocomplete = true;
private boolean mLastEditWasDelete;
private boolean mIgnoreImeForTest;
public AutocompleteEditText(Context context, AttributeSet attrs) {
super(context, attrs);
mAutocompleteSpan = new AutocompleteSpan();
......@@ -418,6 +421,11 @@ public class AutocompleteEditText extends VerticallyFixedEditText {
return mInputConnection;
}
@VisibleForTesting
public void setIgnoreImeForTest(boolean ignore) {
mIgnoreImeForTest = ignore;
}
private InputConnectionWrapper mInputConnection = new InputConnectionWrapper(null, true) {
private final char[] mTempSelectionChar = new char[1];
......@@ -528,9 +536,16 @@ public class AutocompleteEditText extends VerticallyFixedEditText {
@VisibleForTesting
public InputConnection createInputConnection(InputConnection target) {
mInputConnection.setTarget(target);
if (mIgnoreImeForTest) return null;
return mInputConnection;
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (mIgnoreImeForTest) return true;
return super.dispatchKeyEvent(event);
}
private void notifyAutocompleteTextStateChanged(boolean textDeleted, boolean updateDisplay) {
if (DEBUG) {
Log.i(TAG, "notifyAutocompleteTextStateChanged: DEL[%b] DIS[%b] IGN[%b]", textDeleted,
......
......@@ -17,6 +17,7 @@ import android.text.Editable;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.InputMethodManager;
import org.junit.Assert;
import org.junit.Before;
......@@ -66,6 +67,43 @@ public class UrlBarTest {
+ new String(new char[9000]).replace('\0', 'u')
+ "ge!";
// Prevent real keyboard app from interfering with test result. After calling this function,
// real keyboard app will interact with null InputConnection while the test can still interact
// with BaseInputConnection's method and thus affects EditText's Editable through
// {@link UrlBar#getInputConnection()}. https://crbug.com/723901 for details.
private void startIgnoringImeUntilRestart(final UrlBar urlBar) {
urlBar.setIgnoreImeForTest(true);
InputMethodManager imm =
(InputMethodManager) mActivityTestRule.getActivity().getSystemService(
Context.INPUT_METHOD_SERVICE);
imm.restartInput(urlBar);
}
private void toggleFocusAndIgnoreImeOperations(final UrlBar urlBar, final boolean gainFocus) {
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
OmniboxTestUtils.toggleUrlBarFocus(urlBar, gainFocus);
if (gainFocus) startIgnoringImeUntilRestart(urlBar);
}
});
}
private void runInputConnectionMethodOnUiThreadBlocking(final Runnable runnable) {
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
UrlBar urlBar = getUrlBar();
// Note: in order for this to work correctly, the following conditions should be met
// 1) Unset and set ignoreImeForTest within one UI loop.
// 2) Do not restartInput() in between.
urlBar.setIgnoreImeForTest(false);
runnable.run();
urlBar.setIgnoreImeForTest(true);
}
});
}
private UrlBar getUrlBar() {
return (UrlBar) mActivityTestRule.getActivity().findViewById(R.id.url_bar);
}
......@@ -186,7 +224,7 @@ public class UrlBarTest {
mActivityTestRule.startMainActivityOnBlankPage();
stubLocationBarAutocomplete();
final UrlBar urlBar = getUrlBar();
OmniboxTestUtils.toggleUrlBarFocus(urlBar, true);
toggleFocusAndIgnoreImeOperations(urlBar, true);
// Verify that setting a new string will clear the autocomplete.
setTextAndVerifyNoAutocomplete(urlBar, "test");
......@@ -269,9 +307,8 @@ public class UrlBarTest {
public void testAutocompleteUpdatedOnSelection() throws InterruptedException, TimeoutException {
mActivityTestRule.startMainActivityOnBlankPage();
stubLocationBarAutocomplete();
final UrlBar urlBar = getUrlBar();
OmniboxTestUtils.toggleUrlBarFocus(urlBar, true);
toggleFocusAndIgnoreImeOperations(urlBar, true);
// Verify that setting a selection before the autocomplete clears it.
verifySelectionState("test", "ing is fun", 1, 1, false, "test", "test", true, "test");
......@@ -354,7 +391,7 @@ public class UrlBarTest {
setAutocompleteController(controller);
final UrlBar urlBar = getUrlBar();
OmniboxTestUtils.toggleUrlBarFocus(urlBar, true);
toggleFocusAndIgnoreImeOperations(urlBar, true);
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
......@@ -384,7 +421,7 @@ public class UrlBarTest {
stubLocationBarAutocomplete();
final UrlBar urlBar = getUrlBar();
OmniboxTestUtils.toggleUrlBarFocus(urlBar, true);
toggleFocusAndIgnoreImeOperations(urlBar, true);
setTextAndVerifyNoAutocomplete(urlBar, "test");
setAutocomplete(urlBar, "test", "ing");
......@@ -404,8 +441,13 @@ public class UrlBarTest {
};
setAutocompleteController(controller);
KeyUtils.singleKeyEventView(
InstrumentationRegistry.getInstrumentation(), urlBar, KeyEvent.KEYCODE_DEL);
runInputConnectionMethodOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
KeyUtils.singleKeyEventView(
InstrumentationRegistry.getInstrumentation(), urlBar, KeyEvent.KEYCODE_DEL);
}
});
CriteriaHelper.pollUiThread(Criteria.equals("test", new Callable<String>() {
@Override
......@@ -427,7 +469,7 @@ public class UrlBarTest {
mActivityTestRule.startMainActivityOnBlankPage();
stubLocationBarAutocomplete();
final UrlBar urlBar = getUrlBar();
OmniboxTestUtils.toggleUrlBarFocus(urlBar, true);
toggleFocusAndIgnoreImeOperations(urlBar, true);
setTextAndVerifyNoAutocomplete(urlBar, "test");
setAutocomplete(urlBar, "test", "ing is fun");
......@@ -477,7 +519,7 @@ public class UrlBarTest {
setAutocompleteController(controller);
final UrlBar urlBar = getUrlBar();
OmniboxTestUtils.toggleUrlBarFocus(urlBar, true);
toggleFocusAndIgnoreImeOperations(urlBar, true);
setTextAndVerifyNoAutocomplete(urlBar, "test");
setAutocomplete(urlBar, "test", "ing is fun");
......@@ -518,7 +560,7 @@ public class UrlBarTest {
stubLocationBarAutocomplete();
final UrlBar urlBar = getUrlBar();
OmniboxTestUtils.toggleUrlBarFocus(urlBar, true);
toggleFocusAndIgnoreImeOperations(urlBar, true);
OmniboxTestUtils.waitForFocusAndKeyboardActive(urlBar, true);
// Valid case (cursor at the end of text, single character, matches previous autocomplete).
......@@ -594,7 +636,7 @@ public class UrlBarTest {
stubLocationBarAutocomplete();
final UrlBar urlBar = getUrlBar();
OmniboxTestUtils.toggleUrlBarFocus(urlBar, true);
toggleFocusAndIgnoreImeOperations(urlBar, true);
OmniboxTestUtils.waitForFocusAndKeyboardActive(urlBar, true);
setTextAndVerifyNoAutocomplete(urlBar, "a");
......@@ -626,12 +668,12 @@ public class UrlBarTest {
mActivityTestRule.startMainActivityOnBlankPage();
stubLocationBarAutocomplete();
final UrlBar urlBar = getUrlBar();
OmniboxTestUtils.toggleUrlBarFocus(urlBar, true);
toggleFocusAndIgnoreImeOperations(urlBar, true);
// Verify that defocusing the UrlBar clears the autocomplete.
setTextAndVerifyNoAutocomplete(urlBar, "test");
setAutocomplete(urlBar, "test", "ing is fun");
OmniboxTestUtils.toggleUrlBarFocus(urlBar, false);
toggleFocusAndIgnoreImeOperations(urlBar, false);
AutocompleteState state = getAutocompleteState(urlBar, null);
Assert.assertFalse(state.hasAutocomplete);
}
......@@ -645,7 +687,7 @@ public class UrlBarTest {
mActivityTestRule.startMainActivityOnBlankPage();
stubLocationBarAutocomplete();
final UrlBar urlBar = getUrlBar();
OmniboxTestUtils.toggleUrlBarFocus(urlBar, true);
toggleFocusAndIgnoreImeOperations(urlBar, true);
OmniboxTestUtils.waitForFocusAndKeyboardActive(urlBar, true);
setTextAndVerifyNoAutocomplete(urlBar, "test");
......@@ -678,7 +720,7 @@ public class UrlBarTest {
stubLocationBarAutocomplete();
final UrlBar urlBar = getUrlBar();
OmniboxTestUtils.toggleUrlBarFocus(urlBar, true);
toggleFocusAndIgnoreImeOperations(urlBar, true);
OmniboxTestUtils.waitForFocusAndKeyboardActive(urlBar, true);
Assert.assertNotNull(urlBar.getInputConnection());
......@@ -796,7 +838,7 @@ public class UrlBarTest {
UrlBar urlBar = getUrlBar();
Assert.assertNotNull(urlBar);
OmniboxTestUtils.toggleUrlBarFocus(urlBar, true);
toggleFocusAndIgnoreImeOperations(urlBar, true);
OmniboxTestUtils.waitForFocusAndKeyboardActive(urlBar, true);
}
......@@ -806,7 +848,7 @@ public class UrlBarTest {
@RetryOnFailure
public void testCopyHuge() throws InterruptedException {
mActivityTestRule.startMainActivityWithURL(HUGE_URL);
OmniboxTestUtils.toggleUrlBarFocus(getUrlBar(), true);
toggleFocusAndIgnoreImeOperations(getUrlBar(), true);
Assert.assertEquals(HUGE_URL, copyUrlToClipboard(android.R.id.copy));
}
......@@ -816,7 +858,7 @@ public class UrlBarTest {
@RetryOnFailure
public void testCutHuge() throws InterruptedException {
mActivityTestRule.startMainActivityWithURL(HUGE_URL);
OmniboxTestUtils.toggleUrlBarFocus(getUrlBar(), true);
toggleFocusAndIgnoreImeOperations(getUrlBar(), true);
Assert.assertEquals(HUGE_URL, copyUrlToClipboard(android.R.id.cut));
}
......
......@@ -98,7 +98,7 @@ public class KeyUtils {
}
}
});
i.waitForIdleSync();
if (!ThreadUtils.runningOnUiThread()) i.waitForIdleSync();
}
private static void dispatchKeyEventToActivity(final Instrumentation i, final Activity a,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment