1585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov/*
2585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov * Copyright (C) 2010 The Android Open Source Project
3585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov *
4585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov * Licensed under the Apache License, Version 2.0 (the "License");
5585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov * you may not use this file except in compliance with the License.
6585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov * You may obtain a copy of the License at
7585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov *
8585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov *      http://www.apache.org/licenses/LICENSE-2.0
9585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov *
10585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov * Unless required by applicable law or agreed to in writing, software
11585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov * distributed under the License is distributed on an "AS IS" BASIS,
12585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov * See the License for the specific language governing permissions and
14585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov * limitations under the License.
15585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov */
16585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
17585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganovpackage android.webkit;
18585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
19585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganovimport android.accessibilityservice.AccessibilityService;
20585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganovimport android.accessibilityservice.AccessibilityServiceInfo;
21585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganovimport android.content.ComponentName;
22bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganovimport android.content.ContentResolver;
23585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganovimport android.content.Intent;
24585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganovimport android.os.Handler;
25585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganovimport android.os.Looper;
26585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganovimport android.os.SystemClock;
27585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganovimport android.provider.Settings;
288bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganovimport android.test.ActivityInstrumentationTestCase2;
29585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganovimport android.test.suitebuilder.annotation.LargeTest;
30585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganovimport android.view.KeyEvent;
31585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent;
32585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganovimport android.view.accessibility.AccessibilityManager;
33585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
34585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov/**
35585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov * This is a test for the behavior of the {@link AccessibilityInjector}
36585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov * which is used by {@link WebView} to provide basic accessibility support
37585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov * in case JavaScript is disabled.
38585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov * </p>
39585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov * Note: This test works against the generated {@link AccessibilityEvent}s
40585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov *       to so it also checks if the test for announcing navigation axis and
41585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov *       status messages as appropriate.
42585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov */
438bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganovpublic class AccessibilityInjectorTest
448bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov    extends ActivityInstrumentationTestCase2<AccessibilityInjectorTestActivity> {
45585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
46585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    /** The timeout to wait for the expected selection. */
47585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    private static final long TIMEOUT_WAIT_FOR_SELECTION_STRING = 1000;
48585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
49585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    /** The timeout to wait for accessibility and the mock service to be enabled. */
50ea26a4feb6defa465ce13dc3e718f6e9f58269c4Svetoslav Ganov    private static final long TIMEOUT_ENABLE_ACCESSIBILITY_AND_MOCK_SERVICE = 1000;
51585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
52585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    /** The count of tests to detect when to shut down the service. */
538bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov    private static final int TEST_CASE_COUNT = 19;
54585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
55585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    /** The meta state for pressed left ALT. */
56585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    private static final int META_STATE_ALT_LEFT_ON = KeyEvent.META_ALT_ON
57585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            | KeyEvent.META_ALT_LEFT_ON;
58585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
592cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov    /** Prefix for the CSS style span appended by WebKit. */
602cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov    private static final String APPLE_SPAN_PREFIX = "<span class=\"Apple-style-span\"";
612cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov
622cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov    /** Suffix for the CSS style span appended by WebKit. */
632cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov    private static final String APPLE_SPAN_SUFFIX = "</span>";
642cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov
65585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    /** The value for not specified selection string since null is a valid value. */
66585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    private static final String SELECTION_STRING_UNKNOWN = "Unknown";
67585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
68585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    /** Lock for locking the test. */
69585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    private static final Object sTestLock = new Object();
70585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
71bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov    /** Key bindings used for testing. */
72bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov    private static final String TEST_KEY_DINDINGS =
73bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov        "0x13=0x01000100;" +
74bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov        "0x14=0x01010100;" +
75bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov        "0x15=0x04000000;" +
76bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov        "0x16=0x04000000;" +
77bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov        "0x200000013=0x03020701:0x03010201:0x03000101:0x03030001:0x03040001:0x03050001:0x03060001;" +
78bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov        "0x200000014=0x03010001:0x03020101:0x03070201:0x03030701:0x03040701:0x03050701:0x03060701;" +
79bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov        "0x200000015=0x03040301:0x03050401:0x03060501:0x03000601:0x03010601:0x03020601:0x03070601;" +
80bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov        "0x200000016=0x03050601:0x03040501:0x03030401:0x03020301:0x03070301:0x03010301:0x03000301;";
81bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov
82585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    /** Handle to the test for use by the mock service. */
83585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    private static AccessibilityInjectorTest sInstance;
84585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
85585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    /** Flag indicating if the accessibility service is ready to receive events. */
86585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    private static boolean sIsAccessibilityServiceReady;
87585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
88585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    /** The count of executed tests to detect when to toggle accessibility and the service. */
89585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    private static int sExecutedTestCount;
90585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
91585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    /** Worker thread with a handler to perform non test thread processing. */
92585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    private Worker mWorker;
93585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
94585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    /** Handle to the {@link WebView} to load data in. */
95585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    private WebView mWebView;
96585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
97bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov    /** Used for caching the default bindings so they can be restored. */
98f2dd2dfb6cd46166ddbd03d35e9cef98a4c0cbf8Svetoslav Ganov    private static String sDefaultKeyBindings;
99bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov
100585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    /** The received selection string for assertion checking. */
101585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    private static String sReceivedSelectionString = SELECTION_STRING_UNKNOWN;
102585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
1038bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov    public AccessibilityInjectorTest() {
1048bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        super(AccessibilityInjectorTestActivity.class);
1058bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov    }
1068bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
107585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    @Override
108585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    protected void setUp() throws Exception {
109585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        super.setUp();
110585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        mWorker = new Worker();
111585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sInstance = this;
112585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        if (sExecutedTestCount == 0) {
113585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            // until JUnit4 comes to play with @BeforeTest
114585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            disableAccessibilityAndMockAccessibilityService();
115585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            enableAccessibilityAndMockAccessibilityService();
116bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov            injectTestWebContentKeyBindings();
117585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        }
118585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    }
119585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
120585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    @Override
121585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    protected void tearDown() throws Exception {
122585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        if (mWorker != null) {
123585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            mWorker.stop();
124585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        }
125585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        if (sExecutedTestCount == TEST_CASE_COUNT) {
126585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            // until JUnit4 comes to play with @AfterTest
127585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            disableAccessibilityAndMockAccessibilityService();
128bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov            restoreDefaultWebContentKeyBindings();
129585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        }
130585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        super.tearDown();
131585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    }
132585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
133585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    /**
134585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     * Tests navigation by character.
135585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     */
136585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    @LargeTest
137585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    public void testNavigationByCharacter() throws Exception {
138585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // a bit ugly but helps detect beginning and end of all tests so accessibility
139585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // and the mock service are not toggled on every test (expensive)
140585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sExecutedTestCount++;
141585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
142585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        String html =
143585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            "<html>" +
144585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov               "<head>" +
145585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov               "</head>" +
146585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov               "<body>" +
147585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                   "<p>" +
1488bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                      "a<b>b</b>c" +
149585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                   "</p>" +
150585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                   "<p>" +
151585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                     "d" +
1528bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                   "<p/>" +
1538bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                   "e" +
154585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov               "</body>" +
155585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov             "</html>";
156585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
1578bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        WebView webView = loadHTML(html);
158585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
159585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // change navigation axis to word
160585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, META_STATE_ALT_LEFT_ON);
161585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("1"); // expect the word navigation axis
162585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
163585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // change navigation axis to character
164585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, META_STATE_ALT_LEFT_ON);
165585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("0"); // expect the character navigation axis
166585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
167585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the first character
168585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
169585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("a");
170585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
171585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the second character
172585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
173585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<b>b</b>");
174585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
175585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the third character
176585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
177585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("c");
178585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
179585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the fourth character
180585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
181585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("d");
182585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
183585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the fifth character
184585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
185585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("e");
186585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
187585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // try to go past the last character
188585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
189585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString(null);
190585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
1919504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the fifth character (reverse)
1929504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
1939504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("e");
1949504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
195585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the fourth character (reverse)
196585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
197585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("d");
198585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
199585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the third character
200585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
201585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("c");
202585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
203585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the second character
204585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
205585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<b>b</b>");
206585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
207585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the first character
208585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
209585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("a");
210585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
211585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // try to go before the first character
212585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
213585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString(null);
214585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
2159504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the first character
2169504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
2179504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("a");
2189504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
219585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the second character (reverse again)
220585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
221585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<b>b</b>");
222585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    }
223585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
224585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    /**
225585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     * Tests navigation by word.
226585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     */
227585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    @LargeTest
228585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    public void testNavigationByWord() throws Exception {
229585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // a bit ugly but helps detect beginning and end of all tests so accessibility
230585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // and the mock service are not toggled on every test (expensive)
231585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sExecutedTestCount++;
232585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
233585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        String html =
234585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            "<html>" +
235585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov               "<head>" +
236585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov               "</head>" +
237585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov               "<body>" +
238585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                   "<p>" +
239585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                      "This is <b>a</b> sentence" +
240585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                   "</p>" +
241585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                   "<p>" +
242585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                     " scattered " +
2439504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                     "<p/>" +
2449504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                     " all over " +
245585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                   "</p>" +
246585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                   "<div>" +
2479504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                     "<p>the place.</p>" +
248585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                   "</div>" +
249585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov               "</body>" +
250585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov             "</html>";
251585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
2528bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        WebView webView = loadHTML(html);
253585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
254585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // change navigation axis to word
255585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, META_STATE_ALT_LEFT_ON);
256585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("1"); // expect the word navigation axis
257585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
258585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the first word
259585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
260585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("This");
261585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
262585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the second word
263585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
264585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("is");
265585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
266585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the third word
267585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
268585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<b>a</b>");
269585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
270585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the fourth word
271585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
272585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("sentence");
273585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
274585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the fifth word
275585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
276585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("scattered");
277585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
278585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the sixth word
279585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
280585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("all");
281585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
282585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the seventh word
283585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
284585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("over");
285585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
286585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the eight word
287585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
288585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("the");
289585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
290585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the ninth word
291585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
292585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("place");
293585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
294585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // NOTE: WebKit selection returns the dot as a word
295585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
296585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString(".");
297585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
298585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // try to go past the last word
299585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
300585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString(null);
301585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
302585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the last word (reverse)
303585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
3049504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("place.");
305585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
306585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the eight word
307585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
308585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("the");
309585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
310585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the seventh word
311585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
312585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("over");
313585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
314585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the sixth word
315585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
316585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("all");
317585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
318585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the fifth word
319585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
320585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("scattered");
321585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
322585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the fourth word
323585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
324585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("sentence");
325585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
326585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the third word
327585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
328585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<b>a</b>");
329585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
330585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the second word
331585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
332585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("is");
333585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
334585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the first word
335585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
336585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("This");
337585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
338585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // try to go before the first word
339585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
340585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString(null);
341585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
3429504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the first word
3439504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
3449504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("This");
3459504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
346585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the second word (reverse again)
347585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
348585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("is");
349585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    }
350585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
351585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    /**
352585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     * Tests navigation by sentence.
353585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     */
354585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    @LargeTest
355585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    public void testNavigationBySentence() throws Exception {
356585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // a bit ugly but helps detect beginning and end of all tests so accessibility
357585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // and the mock service are not toggled on every test (expensive)
358585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sExecutedTestCount++;
359585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
360585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        String html =
361585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            "<html>" +
362585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov              "<head>" +
363585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov              "</head>" +
364585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov              "<body>" +
365585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "<div>" +
366585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                  "<p>" +
367585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                    "This is the first sentence of the first paragraph and has an <b>inline bold tag</b>." +
368585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                    "This is the second sentence of the first paragraph." +
369585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                  "</p>" +
370585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                  "<h1>This is a heading</h1>" +
371585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                  "<p>" +
372585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                    "This is the first sentence of the second paragraph." +
373585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                    "This is the second sentence of the second paragraph." +
374585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                  "</p>" +
375585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "</div>" +
376585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov              "</body>" +
377585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            "</html>";
378585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
3798bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        WebView webView = loadHTML(html);
380585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
381585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // Sentence axis is the default
382585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
383585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the first sentence
384585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
385585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("This is the first sentence of the first paragraph and has an "
386585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                + "<b>inline bold tag</b>.");
387585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
388585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the second sentence
389585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
390585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("This is the second sentence of the first paragraph.");
391585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
392585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the third sentence
393585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
394585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("This is a heading");
395585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
396585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the fourth sentence
397585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
398585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("This is the first sentence of the second paragraph.");
399585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
400585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the fifth sentence
401585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
402585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("This is the second sentence of the second paragraph.");
403585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
404585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // try to go past the last sentence
405585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
406585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString(null);
407585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
4089504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the fifth sentence
4099504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
4109504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("This is the second sentence of the second paragraph.");
4119504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
412585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the fourth sentence (reverse)
413585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
414585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("This is the first sentence of the second paragraph.");
415585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
416585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the third sentence
417585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
418585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("This is a heading");
419585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
420585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the second sentence
421585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
422585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("This is the second sentence of the first paragraph.");
423585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
424585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the first sentence
425585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
426585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("This is the first sentence of the first paragraph and has an "
427585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                + "<b>inline bold tag</b>.");
428585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
429585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // try to go before the first sentence
430585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
431585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString(null);
432585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
4339504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the first sentence
4349504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
4359504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("This is the first sentence of the first paragraph and has an "
4369504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                + "<b>inline bold tag</b>.");
4379504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
438585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the second sentence (reverse again)
439585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
440585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("This is the second sentence of the first paragraph.");
441585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    }
442585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
443585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    /**
444585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     * Tests navigation by heading.
445585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     */
446585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    @LargeTest
447585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    public void testNavigationByHeading() throws Exception {
448585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // a bit ugly but helps detect beginning and end of all tests so accessibility
449585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // and the mock service are not toggled on every test (expensive)
450585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sExecutedTestCount++;
451585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
452585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        String html =
453585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            "<!DOCTYPE html>" +
454585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            "<html>" +
455585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov              "<head>" +
456585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov              "</head>" +
457585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov              "<body>" +
458585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "<h1>Heading one</h1>" +
459585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "<p>" +
460585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                  "This is some text" +
461585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "</p>" +
462585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "<h2>Heading two</h2>" +
463585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "<p>" +
464585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                  "This is some text" +
465585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "</p>" +
466585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "<h3>Heading three</h3>" +
467585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "<p>" +
468585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                  "This is some text" +
469585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "</p>" +
470585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "<h4>Heading four</h4>" +
471585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "<p>" +
472585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                  "This is some text" +
473585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "</p>" +
474585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "<h5>Heading five</h5>" +
475585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "<p>" +
476585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                  "This is some text" +
477585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "</p>" +
478585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "<h6>Heading six</h6>" +
479585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov              "</body>" +
480585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            "</html>";
481585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
4828bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        WebView webView = loadHTML(html);
483585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
484585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // change navigation axis to heading
485585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_RIGHT, META_STATE_ALT_LEFT_ON);
486585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("3"); // expect the heading navigation axis
487585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
488585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the first heading
489585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
490585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<h1>Heading one</h1>");
491585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
492585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the second heading
493585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
494585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<h2>Heading two</h2>");
495585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
496585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the third heading
497585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
498585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<h3>Heading three</h3>");
499585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
500585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the fourth heading
501585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
502585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<h4>Heading four</h4>");
503585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
504585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the fifth heading
505585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
506585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<h5>Heading five</h5>");
507585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
508585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the sixth heading
509585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
510585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<h6>Heading six</h6>");
511585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
512585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // try to go past the last heading
513585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
514585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString(null);
515585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
516585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the fifth heading (reverse)
517585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
518585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<h5>Heading five</h5>");
519585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
520585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the fourth heading
521585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
522585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<h4>Heading four</h4>");
523585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
524585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the third heading
525585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
526585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<h3>Heading three</h3>");
527585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
528585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the second heading
529585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
530585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<h2>Heading two</h2>");
531585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
532585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the first heading
533585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
534585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<h1>Heading one</h1>");
535585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
536585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // try to go before the first heading
537585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
538585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString(null);
539585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
540585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the second heading (reverse again)
541585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
542585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<h2>Heading two</h2>");
543585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    }
544585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
545585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    /**
546585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     * Tests navigation by sibling.
547585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     */
548585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    @LargeTest
549585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    public void testNavigationBySibing() throws Exception {
550585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // a bit ugly but helps detect beginning and end of all tests so accessibility
551585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // and the mock service are not toggled on every test (expensive)
552585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sExecutedTestCount++;
553585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
554585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        String html =
555585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            "<!DOCTYPE html>" +
556585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            "<html>" +
557585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov              "<head>" +
558585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov              "</head>" +
559585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov              "<body>" +
560585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "<h1>Heading one</h1>" +
561585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "<p>" +
562585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                  "This is some text" +
563585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "</p>" +
564585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "<div>" +
565585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                  "<button>Input</button>" +
566585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "</div>" +
567585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov              "</body>" +
568585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            "</html>";
569585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
5708bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        WebView webView = loadHTML(html);
571585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
572585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // change navigation axis to heading
573585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_RIGHT, META_STATE_ALT_LEFT_ON);
574585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("3"); // expect the heading navigation axis
575585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
576585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // change navigation axis to sibling
577585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_RIGHT, META_STATE_ALT_LEFT_ON);
578585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("4"); // expect the sibling navigation axis
579585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
580585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // change navigation axis to parent/first child
581585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_RIGHT, META_STATE_ALT_LEFT_ON);
582585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("5"); // expect the parent/first child navigation axis
583585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
584585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the first child of the body
585585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
586585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<h1>Heading one</h1>");
587585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
588585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // change navigation axis to sibling
589585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_LEFT, META_STATE_ALT_LEFT_ON);
590585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("4"); // expect the sibling navigation axis
591585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
592585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the next sibling
593585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
594585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<p>This is some text</p>");
595585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
596585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the next sibling
597585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
598585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<div><button>Input</button></div>");
599585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
600585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // try to go past the last sibling
601585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
602585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString(null);
603585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
604585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the previous sibling (reverse)
605585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
606585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<p>This is some text</p>");
607585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
608585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the previous sibling
609585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
610585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<h1>Heading one</h1>");
611585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
612585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // try to go before the previous sibling
613585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
614585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString(null);
615585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
616585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the next sibling (reverse again)
617585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
618585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<p>This is some text</p>");
619585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    }
620585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
621585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    /**
622585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     * Tests navigation by parent/first child.
623585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     */
624585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    @LargeTest
625585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    public void testNavigationByParentFirstChild() throws Exception {
626585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // a bit ugly but helps detect beginning and end of all tests so accessibility
627585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // and the mock service are not toggled on every test (expensive)
628585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sExecutedTestCount++;
629585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
630585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        String html =
631585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            "<!DOCTYPE html>" +
632585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            "<html>" +
633585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov              "<head>" +
634585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov              "</head>" +
635585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov              "<body>" +
636585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "<div>" +
637585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                  "<button>Input</button>" +
638585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "</div>" +
639585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov              "</body>" +
640585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            "</html>";
641585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
6428bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        WebView webView = loadHTML(html);
643585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
644585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // change navigation axis to document
645585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_LEFT, META_STATE_ALT_LEFT_ON);
646585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("6"); // expect the document navigation axis
647585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
648585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // change navigation axis to parent/first child
649585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_LEFT, META_STATE_ALT_LEFT_ON);
650585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("5"); // expect the parent/first child navigation axis
651585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
652585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the first child
653585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
654585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<div><button>Input</button></div>");
655585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
656585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the first child
657585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
658585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<button>Input</button>");
659585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
660585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // try to go to the first child of a leaf element
661585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
662585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString(null);
663585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
664585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the parent (reverse)
665585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
666585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<div><button>Input</button></div>");
667585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
668585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the parent
669585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
670585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<body><div><button>Input</button></div></body>");
671585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
672585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // try to go to the body parent
673585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
674585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString(null);
675585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
676585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the first child (reverse again)
677585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
678585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<div><button>Input</button></div>");
679585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    }
680585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
681585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    /**
682585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     * Tests navigation by document.
683585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     */
684585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    @LargeTest
685585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    public void testNavigationByDocument() throws Exception {
686585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // a bit ugly but helps detect beginning and end of all tests so accessibility
687585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // and the mock service are not toggled on every test (expensive)
688585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sExecutedTestCount++;
689585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
690585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        String html =
691585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            "<!DOCTYPE html>" +
692585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            "<html>" +
693585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov              "<head>" +
694585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov              "</head>" +
695585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov              "<body>" +
696585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "<button>Click</button>" +
697585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov              "</body>" +
698585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            "</html>";
699585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
7008bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        WebView webView = loadHTML(html);
701585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
702585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // change navigation axis to document
703585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_LEFT, META_STATE_ALT_LEFT_ON);
704585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("6"); // expect the document navigation axis
705585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
706585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the bottom of the document
707585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
708585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("Click");
709585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
710585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the top of the document (reverse)
711585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
712585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<body><button>Click</button></body>");
713585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
714585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the bottom of the document (reverse again)
715585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
716585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("Click");
717585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    }
718585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
719585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    /**
720585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     * Tests the sync between the text navigation and navigation by DOM elements.
721585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     */
722585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    @LargeTest
723585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    public void testSyncBetweenTextAndDomNodeNavigation() throws Exception {
724585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // a bit ugly but helps detect beginning and end of all tests so accessibility
725585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // and the mock service are not toggled on every test (expensive)
726585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sExecutedTestCount++;
727585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
728585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        String html =
729585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            "<!DOCTYPE html>" +
730585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            "<html>" +
731585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov              "<head>" +
732585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov              "</head>" +
733585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov              "<body>" +
734585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "<p>" +
735585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                  "First" +
736585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "</p>" +
737585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "<button>Second</button>" +
738585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "<p>" +
739585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                  "Third" +
740585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                "</p>" +
741585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov              "</body>" +
742585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            "</html>";
743585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
7448bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        WebView webView = loadHTML(html);
745585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
746585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // change navigation axis to word
747585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, META_STATE_ALT_LEFT_ON);
748585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("1"); // expect the word navigation axis
749585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
750585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the first word
751585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
752585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("First");
753585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
754585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // change navigation axis to heading
755585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_RIGHT, META_STATE_ALT_LEFT_ON);
756585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("3"); // expect the heading navigation axis
757585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
758585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // change navigation axis to sibling
759585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_RIGHT, META_STATE_ALT_LEFT_ON);
760585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("4"); // expect the sibling navigation axis
761585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
762585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the next sibling
763585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
764585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("<button>Second</button>");
765585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
766585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // change navigation axis to character
767585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, META_STATE_ALT_LEFT_ON);
768585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("0"); // expect the character navigation axis
769585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
770585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // change navigation axis to word
771585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, META_STATE_ALT_LEFT_ON);
772585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("1"); // expect the word navigation axis
773585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
774585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // go to the next word
775585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
776585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertSelectionString("Third");
777585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    }
778585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
779585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    /**
7809504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov     * Tests that the selection does not cross anchor boundaries. This is a
7819504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov     * workaround for the asymmetric and inconsistent handling of text with
7829504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov     * links by WebKit while traversing by sentence.
7839504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov     */
7849504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    @LargeTest
7859504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    public void testEnforceSelectionDoesNotCrossAnchorBoundary1() throws Exception {
7869504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // a bit ugly but helps detect beginning and end of all tests so accessibility
7879504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // and the mock service are not toggled on every test (expensive)
7889504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sExecutedTestCount++;
7899504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
7909504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        String html =
7919504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov            "<!DOCTYPE html>" +
7929504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov            "<html>" +
7939504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "<head>" +
7949504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "</head>" +
7959504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "<body>" +
7969504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "<div>First</div>" +
7979504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "<p>" +
7989504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                  "<a href=\"\">Second</a> Third" +
7999504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "</p>" +
8009504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "</body>" +
8019504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov            "</html>";
8029504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
8038bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        WebView webView = loadHTML(html);
8049504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
8059504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the first sentence
8069504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
8078bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("<div>First</div>");
8089504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
8099504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the second sentence
8109504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
8119504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("<a href=\"\">Second</a>");
8129504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
8139504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the third sentence
8149504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
8159504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("Third");
8169504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
8179504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to past the last sentence
8189504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
8199504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString(null);
8209504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
8219504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the third sentence
8229504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
8239504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("Third");
8249504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
8259504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the second sentence
8269504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
8279504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("<a href=\"\">Second</a>");
8289504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
8299504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the first sentence
8309504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
8319504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("First");
8329504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
8339504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to before the first sentence
8349504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
8359504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString(null);
8369504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
8379504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the first sentence
8389504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
8398bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("<div>First</div>");
8409504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    }
8419504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
8429504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    /**
8439504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov     * Tests that the selection does not cross anchor boundaries. This is a
8449504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov     * workaround for the asymmetric and inconsistent handling of text with
8459504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov     * links by WebKit while traversing by sentence.
8469504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov     */
8479504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    @LargeTest
8489504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    public void testEnforceSelectionDoesNotCrossAnchorBoundary2() throws Exception {
8499504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // a bit ugly but helps detect beginning and end of all tests so accessibility
8509504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // and the mock service are not toggled on every test (expensive)
8519504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sExecutedTestCount++;
8529504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
8539504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        String html =
8549504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov            "<!DOCTYPE html>" +
8559504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov            "<html>" +
8569504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "<head>" +
8579504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "</head>" +
8589504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "<body>" +
8599504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "<div>First</div>" +
8609504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "<a href=\"#\">Second</a>" +
8619504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "&nbsp;" +
8629504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "<a href=\"#\">Third</a>" +
8639504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "</body>" +
8649504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov            "</html>";
8659504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
8668bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        WebView webView = loadHTML(html);
8679504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
8689504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the first sentence
8699504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
8709504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("First");
8719504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
8729504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the second sentence
8739504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
8749504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("<a href=\"#\">Second</a>");
8759504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
8769504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the third sentence
8779504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
8789504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("&nbsp;");
8799504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
8809504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the fourth sentence
8819504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
8829504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("<a href=\"#\">Third</a>");
8839504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
8849504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to past the last sentence
8859504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
8869504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString(null);
8879504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
8889504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the fourth sentence
8899504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
8909504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("<a href=\"#\">Third</a>");
8919504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
8929504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the third sentence
8939504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
8949504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("&nbsp;");
8959504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
8969504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the second sentence
8979504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
8989504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("<a href=\"#\">Second</a>");
8999504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
9009504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the first sentence
9019504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
9029504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("First");
9039504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
9049504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to before the first sentence
9059504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
9069504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString(null);
9079504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
9089504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the first sentence
9099504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
9109504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("First");
9119504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    }
9129504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
9139504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    /**
9149504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov     * Tests that the selection does not cross anchor boundaries. This is a
9159504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov     * workaround for the asymmetric and inconsistent handling of text with
9169504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov     * links by WebKit while traversing by sentence.
9179504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov     */
9189504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    @LargeTest
9199504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    public void testEnforceSelectionDoesNotCrossAnchorBoundary3() throws Exception {
9209504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // a bit ugly but helps detect beginning and end of all tests so accessibility
9219504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // and the mock service are not toggled on every test (expensive)
9229504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sExecutedTestCount++;
9239504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
9249504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        String html =
9259504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov            "<!DOCTYPE html>" +
9269504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov            "<html>" +
9279504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "<head>" +
9289504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "</head>" +
9299504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "<body>" +
9309504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "<div>" +
9319504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                  "First" +
9329504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "<div>" +
9339504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "<div>" +
9349504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                  "<a href=\"#\">Second</a>" +
9359504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "</div>" +
9369504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "<div>" +
9379504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                  "Third" +
9389504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "</div>" +
9399504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "</body>" +
9409504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov            "</html>";
9419504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
9428bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        WebView webView = loadHTML(html);
9439504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
9449504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the first sentence
9459504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
9469504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("First");
9479504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
9489504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the second sentence
9499504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
9509504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("<a href=\"#\">Second</a>");
9519504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
9529504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the third sentence
9539504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
9549504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("Third");
9559504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
9569504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to past the last sentence
9579504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
9589504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString(null);
9599504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
9609504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the third sentence
9619504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
9629504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("Third");
9639504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
9649504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the second sentence
9659504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
9669504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("<a href=\"#\">Second</a>");
9679504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
9689504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the first sentence
9699504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
9709504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("First");
9719504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
9729504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to before the first sentence
9739504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
9749504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString(null);
9759504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
9769504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the first sentence
9779504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
9789504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("First");
9799504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    }
9809504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
9819504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    /**
9829504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov     * Tests skipping of content with hidden visibility.
9839504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov     */
9849504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    @LargeTest
9859504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    public void testSkipVisibilityHidden() throws Exception {
9869504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // a bit ugly but helps detect beginning and end of all tests so accessibility
9879504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // and the mock service are not toggled on every test (expensive)
9889504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sExecutedTestCount++;
9899504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
9909504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        String html =
9919504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov            "<!DOCTYPE html>" +
9929504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov            "<html>" +
9939504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "<head>" +
9949504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "</head>" +
9959504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "<body>" +
9969504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "<div>First </div>" +
9979504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "<div style=\"visibility:hidden;\">Second</div>" +
9989504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "<div> Third</div>" +
9999504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "</body>" +
10009504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov            "</html>";
10019504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
10028bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        WebView webView = loadHTML(html);
10039504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
10049504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // change navigation axis to word
10059504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, META_STATE_ALT_LEFT_ON);
10069504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("1"); // expect the word navigation axis
10079504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
10089504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the first word
10099504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
10109504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("First");
10119504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
10129504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the third word (the second is invisible)
10139504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
10149504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("Third");
10159504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
10169504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to past the last sentence
10179504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
10189504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString(null);
10199504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
10209504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the third word (the second is invisible)
10219504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
10229504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("Third");
10239504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
10249504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the first word
10259504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
10269504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("First");
10279504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
10289504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to before the first word
10299504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
10309504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString(null);
10319504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
10329504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the first word
10339504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
10349504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("First");
10359504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    }
10369504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
10379504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    /**
10389504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov     * Tests skipping of content with display none.
10399504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov     */
10409504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    @LargeTest
10419504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    public void testSkipDisplayNone() throws Exception {
10429504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // a bit ugly but helps detect beginning and end of all tests so accessibility
10439504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // and the mock service are not toggled on every test (expensive)
10449504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sExecutedTestCount++;
10459504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
10469504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        String html =
10479504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov            "<!DOCTYPE html>" +
10489504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov            "<html>" +
10499504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "<head>" +
10509504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "</head>" +
10519504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "<body>" +
10529504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "<div>First</div>" +
10539504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "<div style=\"display: none;\">Second</div>" +
10549504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "<div>Third</div>" +
10559504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "</body>" +
10569504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov            "</html>";
10579504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
10588bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        WebView webView = loadHTML(html);
10599504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
10609504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // change navigation axis to word
10619504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, META_STATE_ALT_LEFT_ON);
10629504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("1"); // expect the word navigation axis
10639504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
10649504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the first word
10659504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
10669504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("First");
10679504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
10689504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the third word (the second is invisible)
10699504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
10709504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("Third");
10719504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
10729504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to past the last sentence
10739504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
10749504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString(null);
10759504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
10769504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the third word (the second is invisible)
10779504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
10789504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("Third");
10799504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
10809504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the first word
10819504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
10829504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("First");
10839504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
10849504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to before the first word
10859504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
10869504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString(null);
10879504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
10889504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the first word
10899504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
10909504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("First");
10919504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    }
10929504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
10939504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    /**
10949504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov     * Tests for the selection not getting stuck.
10959504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov     *
10969504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov     * Note: The selection always proceeds but if it can
10979504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov     * be selecting the same content i.e. between the start
10989504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov     * and end are contained the same text nodes.
10999504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov     */
11009504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    @LargeTest
11019504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    public void testSelectionTextProceed() throws Exception {
11029504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // a bit ugly but helps detect beginning and end of all tests so accessibility
11039504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // and the mock service are not toggled on every test (expensive)
11049504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sExecutedTestCount++;
11059504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
11069504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        String html =
11079504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov            "<!DOCTYPE html>" +
11089504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov            "<html>" +
11099504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "<head>" +
11109504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "</head>" +
11119504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "<body>" +
11129504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "<a href=\"#\">First</a>" +
11139504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "<span><a href=\"#\"><span>Second</span>&nbsp;<small>a</small></a>" +
11149504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "</span>&nbsp;<a href=\"#\">Third</a>" +
11159504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "</body>" +
11169504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov            "</html>";
11179504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
11188bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        WebView webView = loadHTML(html);
11199504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
11209504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the first sentence
11219504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
11229504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("<a href=\"#\">First</a>");
11239504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
11249504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the second sentence
11259504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
11269504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("<a href=\"#\"><span>Second&nbsp;<small>a</small></a>");
11279504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
11289504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the third sentence
11299504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
11309504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("&nbsp;");
11319504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
11329504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the fourth sentence
11339504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
11349504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("<a href=\"#\">Third</a>");
11359504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
11369504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to past the last sentence
11379504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
11389504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString(null);
11399504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
11409504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the third sentence
11419504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
11429504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("<a href=\"#\">Third</a>");
11439504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
11449504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // NOTE: Here we are a bit asymmetric around whitespace but we can live with it
11459504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
11469504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("&nbsp;");
11479504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
11489504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the second sentence
11499504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
11509504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("<a href=\"#\"><span>Second&nbsp;<small>a</small></a>");
11519504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
11529504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the first sentence
11539504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
11549504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("<a href=\"#\">First</a>");
11559504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
11569504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to before the first sentence
11579504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
11589504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString(null);
11599504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
11609504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the first sentence
11619504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
11629504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("<a href=\"#\">First</a>");
11639504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    }
11649504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
11659504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    /**
11669504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov     * Tests if input elements are selected rather skipped.
11679504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov     */
11689504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    @LargeTest
11699504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    public void testSelectionOfInputElements() throws Exception {
11709504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // a bit ugly but helps detect beginning and end of all tests so accessibility
11719504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // and the mock service are not toggled on every test (expensive)
11729504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sExecutedTestCount++;
11739504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
11749504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        String html =
11759504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov            "<!DOCTYPE html>" +
11769504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov            "<html>" +
11779504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "<head>" +
11789504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "</head>" +
11799504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "<body>" +
11809504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "<p>" +
11819504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                  "First" +
11829504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "</p>" +
11839504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "<input type=\"text\"/>" +
11849504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "<p>" +
11859504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                  "Second" +
11869504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "</p>" +
11879504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "</body>" +
11889504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov            "</html>";
11899504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
11908bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        WebView webView = loadHTML(html);
11919504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
11929504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the first sentence
11939504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
11949504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("First");
11959504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
11969504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the second sentence
11979504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
11989504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("<input type=\"text\">");
11999504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
12009504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the third sentence
12019504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
12029504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("Second");
12039504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
12049504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to past the last sentence
12059504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
12069504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString(null);
12079504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
12089504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the third sentence
12099504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
12109504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("Second");
12119504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
12129504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the second sentence
12139504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
12149504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("<input type=\"text\">");
12159504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
12169504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the first sentence
12179504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
12189504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("First");
12199504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
12209504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to before the first sentence
12219504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
12229504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString(null);
12239504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
12249504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the first sentence
12259504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
12269504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("First");
12279504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    }
12289504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
12299504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    /**
12309504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov     * Tests traversing of input controls.
12319504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov     */
12329504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    @LargeTest
12339504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    public void testSelectionOfInputElements2() throws Exception {
12349504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // a bit ugly but helps detect beginning and end of all tests so accessibility
12359504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // and the mock service are not toggled on every test (expensive)
12369504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sExecutedTestCount++;
12379504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
12389504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        String html =
12399504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov            "<!DOCTYPE html>" +
12409504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov            "<html>" +
12419504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "<head>" +
12429504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "</head>" +
12439504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "<body>" +
12449504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "<div>" +
12459504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                  "First" +
12469504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                  "<input type=\"text\"/>" +
12479504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                  "<span>" +
12489504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                    "<input type=\"text\"/>" +
12499504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                  "</span>" +
12509504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                  "<button type=\"button\">Click Me!</button>" +
12519504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                  "<div>" +
12529504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                    "<input type=\"submit\"/>" +
12539504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                  "</div>" +
12549504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                  "<p>" +
12559504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                    "Second" +
12569504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                  "</p>" +
12579504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                "</div>" +
12589504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov              "</body>" +
12599504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov            "</html>";
12609504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
12618bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        WebView webView = loadHTML(html);
12629504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
12639504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the first sentence
12649504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
12659504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("First");
12669504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
12679504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the second sentence
12689504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
12699504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("<input type=\"text\">");
12709504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
12719504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the third sentence
12729504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
12739504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("<input type=\"text\">");
12749504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
12759504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the fourth sentence
12769504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
12779504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("<button type=\"button\">Click Me!</button>");
12789504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
12799504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the fifth sentence
12809504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
12819504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("<input type=\"submit\">");
12829504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
12839504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the sixth sentence
12849504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
12859504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("Second");
12869504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
12879504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to past the last sentence
12889504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
12899504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString(null);
12909504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
12919504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the sixth sentence
12929504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
12939504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("Second");
12949504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
12959504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the fifth sentence
12969504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
12979504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("<input type=\"submit\">");
12989504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
12999504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the fourth sentence
13009504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
13019504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("<button type=\"button\">Click Me!</button>");
13029504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
13039504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the third sentence
13049504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
13059504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("<input type=\"text\">");
13069504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
13078bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the second sentence
13088bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
13098bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("<input type=\"text\">");
13108bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
13118bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the first sentence
13128bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
13138bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("First");
13148bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov    }
13158bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
13168bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov    /**
13178bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov     * Tests traversing of input controls.
13188bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov     */
13198bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov    @LargeTest
13208bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov    public void testSelectionOfInputElements3() throws Exception {
13218bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // a bit ugly but helps detect beginning and end of all tests so accessibility
13228bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // and the mock service are not toggled on every test (expensive)
13238bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sExecutedTestCount++;
13248bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
13258bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        String html =
13268bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov            "<!DOCTYPE html>" +
13278bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov            "<html>" +
13288bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov              "<head>" +
13298bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov              "</head>" +
13308bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov              "<body>" +
13318bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                "<input type=\"text\"/>" +
13328bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                "<button type=\"button\">Click Me!</button>" +
13338bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                "<select>" +
13348bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                  "<option value=\"volvo\">Volvo</option>" +
13358bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                  "<option value=\"saab\">Saab</option>" +
13368bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                "</select>" +
13378bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov              "</body>" +
13388bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov            "</html>";
13398bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
13408bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        WebView webView = loadHTML(html);
13418bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
13428bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the first sentence
13438bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
13448bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("<input type=\"text\">");
13458bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
13468bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the second sentence
13478bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
13488bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("<button type=\"button\">Click Me!</button>");
13498bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
13508bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the third sentence
13518bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
13528bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("<select><option value=\"volvo\">Volvo</option>" +
13538bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                "<option value=\"saab\">Saab</option></select>");
13548bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
13558bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to past the last sentence
13568bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
13578bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString(null);
13588bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
13598bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the third sentence
13608bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
13618bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("<select><option value=\"volvo\">Volvo</option>" +
13628bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                "<option value=\"saab\">Saab</option></select>");
13638bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
13648bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the second sentence
13658bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
13668bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("<button type=\"button\">Click Me!</button>");
13678bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
13688bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the first sentence
13698bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
13708bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("<input type=\"text\">");
13718bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
13728bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to before the first sentence
13738bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
13748bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString(null);
13758bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
13768bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the first sentence
13778bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
13788bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("<input type=\"text\">");
13798bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov    }
13808bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
13818bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov    /**
13828bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov     * Tests traversing of input controls.
13838bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov     */
13848bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov    @LargeTest
13858bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov    public void testSelectionOfInputElements4() throws Exception {
13868bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // a bit ugly but helps detect beginning and end of all tests so accessibility
13878bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // and the mock service are not toggled on every test (expensive)
13888bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sExecutedTestCount++;
13898bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
13908bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        String html =
13918bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov            "<!DOCTYPE html>" +
13928bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov            "<html>" +
13938bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov              "<head>" +
13948bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov              "</head>" +
13958bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov              "<body>" +
13968bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                "Start" +
13978bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                "<span>" +
13988bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                  "<span>" +
13998bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                    "<input type=\"submit\">" +
14008bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                  "</span>" +
14018bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                "</span>" +
14028bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                "<input type=\"text\" size=\"30\">" +
14038bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                "<span>" +
14048bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                  "<span>" +
14058bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                    "<input type=\"submit\" size=\"30\">" +
14068bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                  "</span>" +
14078bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                "</span>" +
14088bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                "End" +
14098bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov              "</body>" +
14108bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov            "</html>";
14118bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
14128bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        WebView webView = loadHTML(html);
14138bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
14148bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the first sentence
14158bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
14168bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("Start");
14178bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
14188bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the second sentence
14198bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
14208bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("<input type=\"submit\">");
14218bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
14228bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the third sentence
14238bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
14248bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("<input type=\"text\" size=\"30\">");
14258bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
14268bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the fourth sentence
14278bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
14288bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("<input type=\"submit\" size=\"30\">");
14298bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
14308bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the fifth sentence
14318bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
14328bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("End");
14338bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
14348bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to past the last sentence
14358bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
14368bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString(null);
14378bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
14388bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the fifth sentence
14398bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
14408bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("End");
14418bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
14428bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the fourth sentence
14438bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
14448bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("<input type=\"submit\" size=\"30\">");
14458bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
14468bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the third sentence
14478bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
14488bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("<input type=\"text\" size=\"30\">");
14498bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
14508bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the second sentence
14518bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
14528bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("<input type=\"submit\">");
14538bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
14548bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the first sentence
14558bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
14568bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("Start");
14578bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
14588bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to before the first sentence
14598bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
14608bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString(null);
14618bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
14628bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the first sentence
14638bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
14648bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("Start");
14658bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov    }
14668bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
14678bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov    /**
14688bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov     * Tests traversing of input controls.
14698bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov     */
14708bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov    @LargeTest
14718bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov    public void testSelectionOfInputElements5() throws Exception {
14728bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // a bit ugly but helps detect beginning and end of all tests so accessibility
14738bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // and the mock service are not toggled on every test (expensive)
14748bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sExecutedTestCount++;
14758bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
14768bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        String html =
14778bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov            "<!DOCTYPE html>" +
14788bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov            "<html>" +
14798bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov              "<head>" +
14808bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov              "</head>" +
14818bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov              "<body>" +
14828bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                "<div>" +
14838bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                  "First" +
14848bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                  "<input type=\"hidden\">" +
14858bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                  "<input type=\"hidden\">" +
14868bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                  "<input type=\"hidden\">" +
14878bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                  "<input type=\"hidden\">" +
14888bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                  "<input type=\"text\">" +
14898bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                  "<span>" +
14908bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                    "<span>" +
14918bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                      "<input type=\"submit\">" +
14928bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                    "</span>" +
14938bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                  "</span>" +
14948bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                "</div>" +
14958bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov              "</body>" +
14968bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov              "Second" +
14978bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov            "</html>";
14988bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
14998bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        WebView webView = loadHTML(html);
15008bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
15018bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the first sentence
15028bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
15038bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("First");
15048bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
15058bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the second sentence
15068bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
15078bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("<input type=\"text\">");
15088bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
15098bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the third sentence
15108bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
15118bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("<input type=\"submit\">");
15128bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
15138bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the fourth sentence
15148bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
15158bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("Second");
15168bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
15178bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to past the last sentence
15188bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
15198bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString(null);
15208bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
15218bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the fourth sentence
15228bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
15238bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("Second");
15248bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
15258bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the third sentence
15268bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
15278bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("<input type=\"submit\">");
15288bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
15298bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the second sentence
15308bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
15318bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("<input type=\"text\">");
15328bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
15339504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        // go to the first sentence
15349504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
15359504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov        assertSelectionString("First");
15368bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
15378bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to before the first sentence
15388bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_UP, 0);
15398bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString(null);
15408bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov
15418bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        // go to the first sentence
15428bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        sendKeyEvent(webView, KeyEvent.KEYCODE_DPAD_DOWN, 0);
15438bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        assertSelectionString("First");
15449504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    }
15459504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov
15469504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov    /**
1547585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     * Enable accessibility and the mock accessibility service.
1548585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     */
1549585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    private void enableAccessibilityAndMockAccessibilityService() {
1550585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // make sure the manager is instantiated so the system initializes it
15518bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        AccessibilityManager.getInstance(getActivity());
1552585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
1553585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // enable accessibility and the mock accessibility service
15548bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        Settings.Secure.putInt(getActivity().getContentResolver(),
1555585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                Settings.Secure.ACCESSIBILITY_ENABLED, 1);
15568bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        String enabledServices = new ComponentName(getActivity().getPackageName(),
1557585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                MockAccessibilityService.class.getName()).flattenToShortString();
15588bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        Settings.Secure.putString(getActivity().getContentResolver(),
1559585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, enabledServices);
1560585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
1561585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // poll within a timeout and let be interrupted in case of success
1562585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        long incrementStep = TIMEOUT_ENABLE_ACCESSIBILITY_AND_MOCK_SERVICE / 5;
1563585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        long start = SystemClock.uptimeMillis();
1564585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        while (SystemClock.uptimeMillis() - start < TIMEOUT_ENABLE_ACCESSIBILITY_AND_MOCK_SERVICE &&
1565585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                !sIsAccessibilityServiceReady) {
1566585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            synchronized (sTestLock) {
1567585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                try {
1568585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                    sTestLock.wait(incrementStep);
1569585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                } catch (InterruptedException ie) {
1570585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                    /* ignore */
1571585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                }
1572585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            }
1573585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        }
1574585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
1575585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        if (!sIsAccessibilityServiceReady) {
1576585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            throw new IllegalStateException("MockAccessibilityService not ready. Did you add " +
1577585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                    "tests and forgot to update AccessibilityInjectorTest#TEST_CASE_COUNT?");
1578585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        }
1579585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    }
1580585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
1581585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    @Override
1582585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    protected void scrubClass(Class<?> testCaseClass) {
1583585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        /* do nothing - avoid superclass behavior */
1584585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    }
1585585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
1586585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    /**
15872cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov     * Strips the apple span appended by WebKit while generating
15882cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov     * the selection markup.
15892cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov     *
15902cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov     * @param markup The markup.
15912cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov     * @return Stripped from apple spans markup.
15922cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov     */
15932cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov    private static String stripAppleSpanFromMarkup(String markup) {
15942cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov        StringBuilder stripped = new StringBuilder(markup);
15952cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov        int prefixBegIdx = stripped.indexOf(APPLE_SPAN_PREFIX);
15962cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov        while (prefixBegIdx >= 0) {
15972cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov            int prefixEndIdx = stripped.indexOf(">", prefixBegIdx) + 1;
15982cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov            stripped.replace(prefixBegIdx, prefixEndIdx, "");
15992cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov            int suffixBegIdx = stripped.lastIndexOf(APPLE_SPAN_SUFFIX);
16002cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov            int suffixEndIdx = suffixBegIdx + APPLE_SPAN_SUFFIX.length();
16012cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov            stripped.replace(suffixBegIdx, suffixEndIdx, "");
16022cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov            prefixBegIdx = stripped.indexOf(APPLE_SPAN_PREFIX);
16032cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov        }
16042cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov        return stripped.toString();
16052cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov    }
16062cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov
16072cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov    /**
1608585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     * Disables accessibility and the mock accessibility service.
1609585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     */
1610585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    private void disableAccessibilityAndMockAccessibilityService() {
1611585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        // disable accessibility and the mock accessibility service
16128bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        Settings.Secure.putInt(getActivity().getContentResolver(),
1613585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                Settings.Secure.ACCESSIBILITY_ENABLED, 0);
16148bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        Settings.Secure.putString(getActivity().getContentResolver(),
1615585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, "");
1616585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    }
1617585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
1618585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    /**
1619585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     * Asserts the next <code>expectedSelectionString</code> to be received.
1620585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     */
1621585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    private void assertSelectionString(String expectedSelectionString) {
1622585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        assertTrue("MockAccessibilityService not ready", sIsAccessibilityServiceReady);
1623585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
1624585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        long incrementStep = TIMEOUT_WAIT_FOR_SELECTION_STRING / 5;
1625585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        long start = SystemClock.uptimeMillis();
1626585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        while (SystemClock.uptimeMillis() - start < TIMEOUT_WAIT_FOR_SELECTION_STRING &&
1627585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                sReceivedSelectionString == SELECTION_STRING_UNKNOWN) {
1628585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            synchronized (sTestLock) {
1629585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                try {
1630585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                    sTestLock.wait(incrementStep);
1631585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                } catch (InterruptedException ie) {
1632585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                    /* ignore */
1633585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                }
1634585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            }
1635585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        }
1636585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        try {
1637585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            if (sReceivedSelectionString == SELECTION_STRING_UNKNOWN) {
1638585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                fail("No selection string received. Expected: " + expectedSelectionString);
1639585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            }
1640585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            assertEquals(expectedSelectionString, sReceivedSelectionString);
1641585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        } finally {
1642585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            sReceivedSelectionString = SELECTION_STRING_UNKNOWN;
1643585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        }
1644585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    }
1645585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
1646585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    /**
1647585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     * Sends a {@link KeyEvent} (up and down) to the {@link WebView}.
1648585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     *
1649585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     * @param keyCode The event key code.
1650585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     */
1651585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    private void sendKeyEvent(WebView webView, int keyCode, int metaState) {
1652585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        webView.onKeyDown(keyCode, new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, keyCode, 1, metaState));
1653585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        webView.onKeyUp(keyCode, new KeyEvent(0, 0, KeyEvent.ACTION_UP, keyCode, 1, metaState));
1654585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    }
1655585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
1656585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    /**
16578bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov     * Loads HTML content in a {@link WebView}.
1658585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     *
1659585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     * @param html The HTML content;
16608bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov     * @return The {@link WebView} view.
1661585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     */
16628bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov    private WebView loadHTML(final String html) {
1663585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        mWorker.getHandler().post(new Runnable() {
1664585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            public void run() {
16658bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                if (mWebView == null) {
16668bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                    mWebView = getActivity().getWebView();
16678bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                    mWebView.setWebViewClient(new WebViewClient() {
16688bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                        @Override
16698bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                        public void onPageFinished(WebView view, String url) {
16708bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                            mWorker.getHandler().post(new Runnable() {
16718bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                                public void run() {
16728bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                                    synchronized (sTestLock) {
16738bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                                        sTestLock.notifyAll();
16748bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                                    }
1675585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                                }
16768bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                            });
16778bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                        }
16788bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                    });
16798bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov                }
1680136b1637f89e493b29cc130d1fff066f981ce3e9Steve Block                mWebView.loadData(html, "text/html", null);
1681585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            }
1682585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        });
1683585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        synchronized (sTestLock) {
1684585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            try {
1685585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                sTestLock.wait();
1686585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            } catch (InterruptedException ie) {
1687585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                /* ignore */
1688585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            }
1689585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        }
1690585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        return mWebView;
1691585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    }
1692585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
1693585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    /**
1694bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov     * Injects web content key bindings used for testing. This is required
1695bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov     * to ensure that this test will be agnostic to changes of the bindings.
1696bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov     */
1697bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov    private void injectTestWebContentKeyBindings() {
16988bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        ContentResolver contentResolver = getActivity().getContentResolver();
1699f2dd2dfb6cd46166ddbd03d35e9cef98a4c0cbf8Svetoslav Ganov        sDefaultKeyBindings = Settings.Secure.getString(contentResolver,
1700bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov                Settings.Secure.ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS);
1701bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov        Settings.Secure.putString(contentResolver,
1702bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov                Settings.Secure.ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS, TEST_KEY_DINDINGS);
1703bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov    }
1704bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov
1705bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov    /**
1706bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov     * Restores the default web content key bindings.
1707bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov     */
1708bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov    private void restoreDefaultWebContentKeyBindings() {
17098bf7cace20c84506c7cf8db95a0f4e894dbc2fcaSvetoslav Ganov        Settings.Secure.putString(getActivity().getContentResolver(),
17109504f5753db3309b67e74ccecb400a18d23ca2d1Svetoslav Ganov                Settings.Secure.ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS,
1711f2dd2dfb6cd46166ddbd03d35e9cef98a4c0cbf8Svetoslav Ganov                sDefaultKeyBindings);
1712bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov    }
1713bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov
1714bfc3ce78f4b9b4a720e48b3cc276e81a3fa8cfb2Svetoslav Ganov    /**
1715585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     * This is a worker thread responsible for creating the {@link WebView}.
1716585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     */
1717585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    private class Worker implements Runnable {
1718585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        private final Object mWorkerLock = new Object();
1719585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        private Handler mHandler;
1720585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
1721585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov       public Worker() {
1722585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            new Thread(this).start();
1723585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            synchronized (mWorkerLock) {
1724585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                while (mHandler == null) {
1725585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                    try {
1726585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                        mWorkerLock.wait();
1727585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                    } catch (InterruptedException ex) {
1728585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                        /* ignore */
1729585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                    }
1730585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                }
1731585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            }
1732585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        }
1733585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
1734585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        public void run() {
1735585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            synchronized (mWorkerLock) {
1736585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                Looper.prepare();
1737585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                mHandler = new Handler();
1738585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                mWorkerLock.notifyAll();
1739585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            }
1740585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            Looper.loop();
1741585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        }
1742585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
1743585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        public Handler getHandler() {
1744585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            return mHandler;
1745585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        }
1746585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
1747585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        public void stop() {
1748585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            mHandler.getLooper().quit();
1749585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        }
1750585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    }
1751585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
1752585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    /**
1753585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     * Mock accessibility service to receive the accessibility events
1754585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     * with the current {@link WebView} selection.
1755585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov     */
1756585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    public static class MockAccessibilityService extends AccessibilityService {
1757585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        private boolean mIsServiceInfoSet;
1758585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
1759585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        @Override
1760585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        protected void onServiceConnected() {
1761585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            if (mIsServiceInfoSet) {
1762585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                return;
1763585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            }
1764585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            AccessibilityServiceInfo info = new AccessibilityServiceInfo();
1765585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            info.eventTypes = AccessibilityEvent.TYPE_VIEW_SELECTED;
1766585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
1767585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            setServiceInfo(info);
1768585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            mIsServiceInfoSet = true;
1769585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
1770585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            sIsAccessibilityServiceReady = true;
1771585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
1772585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            if (sInstance == null) {
1773585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                return;
1774585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            }
1775585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            synchronized (sTestLock) {
1776585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                sTestLock.notifyAll();
1777585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            }
1778585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        }
1779585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
1780585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        @Override
1781585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        public void onAccessibilityEvent(AccessibilityEvent event) {
1782585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            if (sInstance == null) {
1783585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                return;
1784585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            }
1785585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            if (!event.getText().isEmpty()) {
1786585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                CharSequence text = event.getText().get(0);
17872cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov                if (text != null) {
17882cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov                    sReceivedSelectionString = stripAppleSpanFromMarkup(text.toString());
17892cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov                } else {
17902cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov                    sReceivedSelectionString = null;
17912cfed9eb0e1316f9906eacf25b51231c1ed8b331Svetoslav Ganov                }
1792585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            }
1793585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            synchronized (sTestLock) {
1794585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov                sTestLock.notifyAll();
1795585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            }
1796585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        }
1797585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
1798585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        @Override
1799585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        public void onInterrupt() {
1800585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            /* do nothing */
1801585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        }
1802585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov
1803585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        @Override
1804585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        public boolean onUnbind(Intent intent) {
1805585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            sIsAccessibilityServiceReady = false;
1806585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov            return false;
1807585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov        }
1808585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov    }
1809585f13f8dec4cbf55b3bc04d95425d647f0577b2Svetoslav Ganov}
1810