1 /**
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the
10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
11  * express or implied. See the License for the specific language governing permissions and
12  * limitations under the License.
13  */
14 
15 package android.accessibilityservice.cts;
16 
17 import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.launchActivityAndWaitForItToBeOnscreen;
18 import static android.accessibilityservice.cts.utils.AsyncUtils.DEFAULT_TIMEOUT_MS;
19 
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertFalse;
22 import static org.junit.Assert.assertNotNull;
23 import static org.junit.Assert.assertSame;
24 import static org.junit.Assert.assertTrue;
25 
26 import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
27 import android.accessibilityservice.cts.activities.AccessibilityTextTraversalActivity;
28 import android.app.Instrumentation;
29 import android.app.UiAutomation;
30 import android.content.pm.PackageManager;
31 import android.os.Bundle;
32 import android.platform.test.annotations.Presubmit;
33 import android.text.Selection;
34 import android.text.TextUtils;
35 import android.view.View;
36 import android.view.accessibility.AccessibilityEvent;
37 import android.view.accessibility.AccessibilityNodeInfo;
38 import android.widget.EditText;
39 import android.widget.TextView;
40 
41 import androidx.test.InstrumentationRegistry;
42 import androidx.test.filters.MediumTest;
43 import androidx.test.rule.ActivityTestRule;
44 import androidx.test.runner.AndroidJUnit4;
45 
46 import com.android.compatibility.common.util.CddTest;
47 
48 import org.junit.AfterClass;
49 import org.junit.Before;
50 import org.junit.BeforeClass;
51 import org.junit.Rule;
52 import org.junit.Test;
53 import org.junit.rules.RuleChain;
54 import org.junit.runner.RunWith;
55 
56 /**
57  * Test cases for testing the accessibility APIs for traversing the text content of
58  * a View at several granularities.
59  */
60 @RunWith(AndroidJUnit4.class)
61 @CddTest(requirements = {"3.10/C-1-1,C-1-2"})
62 @Presubmit
63 public class AccessibilityTextTraversalTest {
64     // The number of characters per page may vary with font, so this number is slightly uncertain.
65     // We need some threshold, however, to make sure moving by a page isn't just moving by a line.
66     private static final int[] CHARACTER_INDICES_OF_PAGE_START = {0, 53, 122, 178};
67 
68     private static Instrumentation sInstrumentation;
69     private static UiAutomation sUiAutomation;
70 
71     private AccessibilityTextTraversalActivity mActivity;
72 
73     private ActivityTestRule<AccessibilityTextTraversalActivity> mActivityRule =
74             new ActivityTestRule<>(AccessibilityTextTraversalActivity.class, false, false);
75 
76     private AccessibilityDumpOnFailureRule mDumpOnFailureRule =
77             new AccessibilityDumpOnFailureRule();
78 
79     @Rule
80     public final RuleChain mRuleChain = RuleChain
81             .outerRule(mActivityRule)
82             .around(mDumpOnFailureRule);
83 
84     @BeforeClass
oneTimeSetup()85     public static void oneTimeSetup() throws Exception {
86         sInstrumentation = InstrumentationRegistry.getInstrumentation();
87         sUiAutomation = sInstrumentation.getUiAutomation();
88     }
89 
90     @AfterClass
postTestTearDown()91     public static void postTestTearDown() {
92         sUiAutomation.destroy();
93     }
94 
95     @Before
setUp()96     public void setUp() throws Exception {
97         mActivity = launchActivityAndWaitForItToBeOnscreen(
98                 sInstrumentation, sUiAutomation, mActivityRule);
99     }
100 
101     @MediumTest
102     @Test
testActionNextAndPreviousAtGranularityCharacterOverContentDescription()103     public void testActionNextAndPreviousAtGranularityCharacterOverContentDescription()
104             throws Exception {
105         final View view = mActivity.findViewById(R.id.view);
106 
107         sInstrumentation.runOnMainSync(new Runnable() {
108             @Override
109             public void run() {
110                 view.setVisibility(View.VISIBLE);
111                 view.setContentDescription(getString(R.string.a_b));
112             }
113         });
114 
115         final AccessibilityNodeInfo text = sUiAutomation
116                 .getRootInActiveWindow().findAccessibilityNodeInfosByText(
117                         getString(R.string.a_b)).get(0);
118 
119         final int granularities = text.getMovementGranularities();
120         assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
121                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
122                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
123 
124         final Bundle arguments = new Bundle();
125         arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
126                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
127 
128         // Move to the next character and wait for an event.
129         AccessibilityEvent firstExpected = sUiAutomation
130                 .executeAndWaitForEvent(new Runnable() {
131             @Override
132             public void run() {
133                 text.performAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY,
134                         arguments);
135             }
136         }, new UiAutomation.AccessibilityEventFilter() {
137             @Override
138             public boolean accept(AccessibilityEvent event) {
139                 return
140                 (event.getEventType() ==
141                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
142                         && event.getAction() ==
143                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
144                         && event.getPackageName().equals(mActivity.getPackageName())
145                         && event.getClassName().equals(View.class.getName())
146                         && event.getContentDescription().toString().equals(
147                                 getString(R.string.a_b))
148                         && event.getFromIndex() == 0
149                         && event.getToIndex() == 1
150                         && event.getMovementGranularity() ==
151                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
152             }
153         }, DEFAULT_TIMEOUT_MS);
154 
155         // Make sure we got the expected event.
156         assertNotNull(firstExpected);
157 
158         // Move to the next character and wait for an event.
159         AccessibilityEvent secondExpected = sUiAutomation
160                 .executeAndWaitForEvent(new Runnable() {
161             @Override
162             public void run() {
163                 text.performAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY,
164                         arguments);
165             }
166         }, new UiAutomation.AccessibilityEventFilter() {
167             @Override
168             public boolean accept(AccessibilityEvent event) {
169                 return
170                 (event.getEventType() ==
171                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
172                         && event.getAction() ==
173                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
174                         && event.getPackageName().equals(mActivity.getPackageName())
175                         && event.getClassName().equals(View.class.getName())
176                         && event.getContentDescription().toString().equals(
177                                 getString(R.string.a_b))
178                         && event.getFromIndex() == 1
179                         && event.getToIndex() == 2
180                         && event.getMovementGranularity() ==
181                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
182             }
183         }, DEFAULT_TIMEOUT_MS);
184 
185         // Make sure we got the expected event.
186         assertNotNull(secondExpected);
187 
188         // Move to the next character and wait for an event.
189         AccessibilityEvent thirdExpected = sUiAutomation
190                 .executeAndWaitForEvent(new Runnable() {
191             @Override
192             public void run() {
193                 text.performAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY,
194                         arguments);
195             }
196         }, new UiAutomation.AccessibilityEventFilter() {
197             @Override
198             public boolean accept(AccessibilityEvent event) {
199                 return
200                 (event.getEventType() ==
201                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
202                         && event.getAction() ==
203                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
204                         && event.getPackageName().equals(mActivity.getPackageName())
205                         && event.getClassName().equals(View.class.getName())
206                         && event.getContentDescription().toString().equals(
207                                 getString(R.string.a_b))
208                         && event.getFromIndex() == 2
209                         && event.getToIndex() == 3
210                         && event.getMovementGranularity() ==
211                                  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
212             }
213         }, DEFAULT_TIMEOUT_MS);
214 
215         // Make sure we got the expected event.
216         assertNotNull(thirdExpected);
217 
218         // Make sure there is no next.
219         assertFalse(text.performAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY,
220                 arguments));
221 
222         // Move to the previous character and wait for an event.
223         AccessibilityEvent fourthExpected = sUiAutomation
224                 .executeAndWaitForEvent(new Runnable() {
225             @Override
226             public void run() {
227                 text.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
228                         arguments);
229             }
230         }, new UiAutomation.AccessibilityEventFilter() {
231             @Override
232             public boolean accept(AccessibilityEvent event) {
233                 return
234                 (event.getEventType() ==
235                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
236                         && event.getAction() ==
237                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
238                         && event.getPackageName().equals(mActivity.getPackageName())
239                         && event.getClassName().equals(View.class.getName())
240                         && event.getContentDescription().toString().equals(
241                                 getString(R.string.a_b))
242                         && event.getFromIndex() == 2
243                         && event.getToIndex() == 3
244                         && event.getMovementGranularity() ==
245                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
246             }
247         }, DEFAULT_TIMEOUT_MS);
248 
249         // Make sure we got the expected event.
250         assertNotNull(fourthExpected);
251 
252         // Move to the previous character and wait for an event.
253         AccessibilityEvent fifthExpected = sUiAutomation
254                 .executeAndWaitForEvent(new Runnable() {
255             @Override
256             public void run() {
257                 text.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
258                         arguments);
259             }
260         }, new UiAutomation.AccessibilityEventFilter() {
261             @Override
262             public boolean accept(AccessibilityEvent event) {
263                 return
264                 (event.getEventType() ==
265                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
266                         && event.getAction() ==
267                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
268                         && event.getPackageName().equals(mActivity.getPackageName())
269                         && event.getClassName().equals(View.class.getName())
270                         && event.getContentDescription().toString().equals(
271                                 getString(R.string.a_b))
272                         && event.getFromIndex() == 1
273                         && event.getToIndex() == 2
274                         && event.getMovementGranularity() ==
275                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
276             }
277         }, DEFAULT_TIMEOUT_MS);
278 
279         // Make sure we got the expected event.
280         assertNotNull(fifthExpected);
281 
282         // Move to the next character and wait for an event.
283         AccessibilityEvent sixthExpected = sUiAutomation
284                 .executeAndWaitForEvent(new Runnable() {
285             @Override
286             public void run() {
287                 text.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
288                         arguments);
289             }
290         }, new UiAutomation.AccessibilityEventFilter() {
291             @Override
292             public boolean accept(AccessibilityEvent event) {
293                 return
294                 (event.getEventType() ==
295                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
296                         && event.getAction() ==
297                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
298                         && event.getPackageName().equals(mActivity.getPackageName())
299                         && event.getClassName().equals(View.class.getName())
300                         && event.getContentDescription().toString().equals(
301                                 getString(R.string.a_b))
302                         && event.getFromIndex() == 0
303                         && event.getToIndex() == 1
304                         && event.getMovementGranularity() ==
305                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
306             }
307         }, DEFAULT_TIMEOUT_MS);
308 
309         // Make sure we got the expected event.
310         assertNotNull(sixthExpected);
311 
312         // Make sure there is no previous.
313         assertFalse(text.performAction(
314                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
315     }
316 
317     @MediumTest
318     @Test
testActionNextAndPreviousAtGranularityWordOverContentDescription()319     public void testActionNextAndPreviousAtGranularityWordOverContentDescription()
320             throws Exception {
321         final View view = mActivity.findViewById(R.id.view);
322 
323         sInstrumentation.runOnMainSync(new Runnable() {
324             @Override
325             public void run() {
326                 view.setVisibility(View.VISIBLE);
327                 view.setContentDescription(getString(R.string.foo_bar_baz));
328             }
329         });
330 
331         final AccessibilityNodeInfo text = sUiAutomation
332                 .getRootInActiveWindow().findAccessibilityNodeInfosByText(
333                         getString(R.string.foo_bar_baz)).get(0);
334 
335         final int granularities = text.getMovementGranularities();
336         assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
337                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
338                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
339 
340         final Bundle arguments = new Bundle();
341         arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
342                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
343 
344         // Move to the next character and wait for an event.
345         AccessibilityEvent firstExpected = sUiAutomation
346                 .executeAndWaitForEvent(new Runnable() {
347             @Override
348             public void run() {
349                 text.performAction(
350                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
351             }
352         }, new UiAutomation.AccessibilityEventFilter() {
353             @Override
354             public boolean accept(AccessibilityEvent event) {
355                 return
356                 (event.getEventType() ==
357                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
358                         && event.getAction() ==
359                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
360                         && event.getPackageName().equals(mActivity.getPackageName())
361                         && event.getClassName().equals(View.class.getName())
362                         && event.getContentDescription().toString().equals(
363                                 getString(R.string.foo_bar_baz))
364                         && event.getFromIndex() == 0
365                         && event.getToIndex() == 3
366                         && event.getMovementGranularity() ==
367                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
368             }
369         }, DEFAULT_TIMEOUT_MS);
370 
371         // Make sure we got the expected event.
372         assertNotNull(firstExpected);
373 
374         // Move to the next character and wait for an event.
375         AccessibilityEvent secondExpected = sUiAutomation
376                 .executeAndWaitForEvent(new Runnable() {
377             @Override
378             public void run() {
379                 text.performAction(
380                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
381             }
382         }, new UiAutomation.AccessibilityEventFilter() {
383             @Override
384             public boolean accept(AccessibilityEvent event) {
385                 return
386                 (event.getEventType() ==
387                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
388                         && event.getAction() ==
389                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
390                         && event.getPackageName().equals(mActivity.getPackageName())
391                         && event.getClassName().equals(View.class.getName())
392                         && event.getContentDescription().toString().equals(
393                                 getString(R.string.foo_bar_baz))
394                         && event.getFromIndex() == 4
395                         && event.getToIndex() == 7
396                         && event.getMovementGranularity() ==
397                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
398             }
399         }, DEFAULT_TIMEOUT_MS);
400 
401         // Make sure we got the expected event.
402         assertNotNull(secondExpected);
403 
404         // Move to the next character and wait for an event.
405         AccessibilityEvent thirdExpected = sUiAutomation
406                 .executeAndWaitForEvent(new Runnable() {
407             @Override
408             public void run() {
409                 text.performAction(
410                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
411             }
412         }, new UiAutomation.AccessibilityEventFilter() {
413             @Override
414             public boolean accept(AccessibilityEvent event) {
415                 return
416                 (event.getEventType() ==
417                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
418                         && event.getAction() ==
419                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
420                         && event.getPackageName().equals(mActivity.getPackageName())
421                         && event.getClassName().equals(View.class.getName())
422                         && event.getContentDescription().toString().equals(
423                                 getString(R.string.foo_bar_baz))
424                         && event.getFromIndex() == 8
425                         && event.getToIndex() == 11
426                         && event.getMovementGranularity() ==
427                                AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
428             }
429         }, DEFAULT_TIMEOUT_MS);
430 
431         // Make sure we got the expected event.
432         assertNotNull(thirdExpected);
433 
434         // Make sure there is no next.
435         assertFalse(text.performAction(
436                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
437 
438         // Move to the next character and wait for an event.
439         AccessibilityEvent fourthExpected = sUiAutomation
440                 .executeAndWaitForEvent(new Runnable() {
441             @Override
442             public void run() {
443                 text.performAction(
444                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
445             }
446         }, new UiAutomation.AccessibilityEventFilter() {
447             @Override
448             public boolean accept(AccessibilityEvent event) {
449                 return
450                 (event.getEventType() ==
451                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
452                         && event.getAction() ==
453                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
454                         && event.getPackageName().equals(mActivity.getPackageName())
455                         && event.getClassName().equals(View.class.getName())
456                         && event.getContentDescription().toString().equals(
457                                 getString(R.string.foo_bar_baz))
458                         && event.getFromIndex() == 8
459                         && event.getToIndex() == 11
460                         && event.getMovementGranularity() ==
461                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
462             }
463         }, DEFAULT_TIMEOUT_MS);
464 
465         // Make sure we got the expected event.
466         assertNotNull(fourthExpected);
467 
468         // Move to the next character and wait for an event.
469         AccessibilityEvent fifthExpected = sUiAutomation
470                 .executeAndWaitForEvent(new Runnable() {
471             @Override
472             public void run() {
473                 text.performAction(
474                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
475             }
476         }, new UiAutomation.AccessibilityEventFilter() {
477             @Override
478             public boolean accept(AccessibilityEvent event) {
479                 return
480                 (event.getEventType() ==
481                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
482                         && event.getAction() ==
483                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
484                         && event.getPackageName().equals(mActivity.getPackageName())
485                         && event.getClassName().equals(View.class.getName())
486                         && event.getContentDescription().toString().equals(
487                                 getString(R.string.foo_bar_baz))
488                         && event.getFromIndex() == 4
489                         && event.getToIndex() == 7
490                         && event.getMovementGranularity() ==
491                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
492             }
493         }, DEFAULT_TIMEOUT_MS);
494 
495         // Make sure we got the expected event.
496         assertNotNull(fifthExpected);
497 
498         // Move to the next character and wait for an event.
499         AccessibilityEvent sixthExpected = sUiAutomation
500                 .executeAndWaitForEvent(new Runnable() {
501             @Override
502             public void run() {
503                 text.performAction(
504                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
505             }
506         }, new UiAutomation.AccessibilityEventFilter() {
507             @Override
508             public boolean accept(AccessibilityEvent event) {
509                 return
510                 (event.getEventType() ==
511                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
512                         && event.getAction() ==
513                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
514                         && event.getPackageName().equals(mActivity.getPackageName())
515                         && event.getClassName().equals(View.class.getName())
516                         && event.getContentDescription().toString().equals(
517                                 getString(R.string.foo_bar_baz))
518                         && event.getFromIndex() == 0
519                         && event.getToIndex() == 3
520                         && event.getMovementGranularity() ==
521                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
522             }
523         }, DEFAULT_TIMEOUT_MS);
524 
525         // Make sure we got the expected event.
526         assertNotNull(sixthExpected);
527 
528         // Make sure there is no previous.
529         assertFalse(text.performAction(
530                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
531     }
532 
533     @MediumTest
534     @Test
testActionNextAndPreviousAtGranularityCharacterOverText()535     public void testActionNextAndPreviousAtGranularityCharacterOverText()
536             throws Exception {
537         final TextView textView = (TextView) mActivity.findViewById(R.id.text);
538 
539         sInstrumentation.runOnMainSync(new Runnable() {
540             @Override
541             public void run() {
542                 textView.setVisibility(View.VISIBLE);
543                 textView.setText(getString(R.string.a_b));
544             }
545         });
546 
547         final AccessibilityNodeInfo text = sUiAutomation
548                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
549                        getString(R.string.a_b)).get(0);
550 
551         final int granularities = text.getMovementGranularities();
552         assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
553                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
554                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
555                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
556                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
557 
558         final Bundle arguments = new Bundle();
559         arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
560                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
561 
562         // Move to the next character and wait for an event.
563         AccessibilityEvent firstExpected = sUiAutomation
564                 .executeAndWaitForEvent(new Runnable() {
565             @Override
566             public void run() {
567                 text.performAction(
568                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
569             }
570         }, new UiAutomation.AccessibilityEventFilter() {
571             @Override
572             public boolean accept(AccessibilityEvent event) {
573                 return
574                 (event.getEventType() ==
575                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
576                         && event.getAction() ==
577                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
578                         && event.getPackageName().equals(mActivity.getPackageName())
579                         && event.getClassName().equals(TextView.class.getName())
580                         && event.getText().size() > 0
581                         && event.getText().get(0).toString().equals(getString(R.string.a_b))
582                         && event.getFromIndex() == 0
583                         && event.getToIndex() == 1
584                         && event.getMovementGranularity() ==
585                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
586             }
587         }, DEFAULT_TIMEOUT_MS);
588 
589         // Make sure we got the expected event.
590         assertNotNull(firstExpected);
591 
592         // Verify the selection position.
593         assertEquals(1, Selection.getSelectionStart(textView.getText()));
594         assertEquals(1, Selection.getSelectionEnd(textView.getText()));
595 
596         // Move to the next character and wait for an event.
597         AccessibilityEvent secondExpected = sUiAutomation
598                 .executeAndWaitForEvent(new Runnable() {
599             @Override
600             public void run() {
601                 text.performAction(
602                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
603             }
604         }, new UiAutomation.AccessibilityEventFilter() {
605             @Override
606             public boolean accept(AccessibilityEvent event) {
607                 return
608                 (event.getEventType() ==
609                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
610                         && event.getAction() ==
611                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
612                         && event.getPackageName().equals(mActivity.getPackageName())
613                         && event.getClassName().equals(TextView.class.getName())
614                         && event.getText().size() > 0
615                         && event.getText().get(0).toString().equals(getString(R.string.a_b))
616                         && event.getFromIndex() == 1
617                         && event.getToIndex() == 2
618                         && event.getMovementGranularity() ==
619                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
620             }
621         }, DEFAULT_TIMEOUT_MS);
622 
623         // Make sure we got the expected event.
624         assertNotNull(secondExpected);
625 
626         // Verify the selection position.
627         assertEquals(2, Selection.getSelectionStart(textView.getText()));
628         assertEquals(2, Selection.getSelectionEnd(textView.getText()));
629 
630         // Move to the next character and wait for an event.
631         AccessibilityEvent thirdExpected = sUiAutomation
632                 .executeAndWaitForEvent(new Runnable() {
633             @Override
634             public void run() {
635                 text.performAction(
636                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
637             }
638         }, new UiAutomation.AccessibilityEventFilter() {
639             @Override
640             public boolean accept(AccessibilityEvent event) {
641                 return
642                 (event.getEventType() ==
643                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
644                         && event.getAction() ==
645                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
646                         && event.getPackageName().equals(mActivity.getPackageName())
647                         && event.getClassName().equals(TextView.class.getName())
648                         && event.getText().size() > 0
649                         && event.getText().get(0).toString().equals(getString(R.string.a_b))
650                         && event.getFromIndex() == 2
651                         && event.getToIndex() == 3
652                         && event.getMovementGranularity() ==
653                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
654             }
655         }, DEFAULT_TIMEOUT_MS);
656 
657         // Make sure we got the expected event.
658         assertNotNull(thirdExpected);
659 
660         // Verify the selection position.
661         assertEquals(3, Selection.getSelectionStart(textView.getText()));
662         assertEquals(3, Selection.getSelectionEnd(textView.getText()));
663 
664         // Make sure there is no next.
665         assertFalse(text.performAction(
666                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
667 
668         // Verify the selection position.
669         assertEquals(3, Selection.getSelectionStart(textView.getText()));
670         assertEquals(3, Selection.getSelectionEnd(textView.getText()));
671 
672         // Move to the previous character and wait for an event.
673         AccessibilityEvent fifthExpected = sUiAutomation
674                 .executeAndWaitForEvent(new Runnable() {
675             @Override
676             public void run() {
677                 text.performAction(
678                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
679             }
680         }, new UiAutomation.AccessibilityEventFilter() {
681             @Override
682             public boolean accept(AccessibilityEvent event) {
683                 return
684                 (event.getEventType() ==
685                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
686                         && event.getAction() ==
687                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
688                         && event.getPackageName().equals(mActivity.getPackageName())
689                         && event.getClassName().equals(TextView.class.getName())
690                         && event.getText().size() > 0
691                         && event.getText().get(0).toString().equals(getString(R.string.a_b))
692                         && event.getFromIndex() == 2
693                         && event.getToIndex() == 3
694                         && event.getMovementGranularity() ==
695                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
696             }
697         }, DEFAULT_TIMEOUT_MS);
698 
699         // Make sure we got the expected event.
700         assertNotNull(fifthExpected);
701 
702         // Verify the selection position.
703         assertEquals(2, Selection.getSelectionStart(textView.getText()));
704         assertEquals(2, Selection.getSelectionEnd(textView.getText()));
705 
706         // Move to the previous character and wait for an event.
707         AccessibilityEvent sixthExpected = sUiAutomation
708                 .executeAndWaitForEvent(new Runnable() {
709             @Override
710             public void run() {
711                 text.performAction(
712                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
713             }
714         }, new UiAutomation.AccessibilityEventFilter() {
715             @Override
716             public boolean accept(AccessibilityEvent event) {
717                 return
718                 (event.getEventType() ==
719                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
720                         && event.getAction() ==
721                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
722                         && event.getPackageName().equals(mActivity.getPackageName())
723                         && event.getClassName().equals(TextView.class.getName())
724                         && event.getText().size() > 0
725                         && event.getText().get(0).toString().equals(getString(R.string.a_b))
726                         && event.getFromIndex() == 1
727                         && event.getToIndex() == 2
728                         && event.getMovementGranularity() ==
729                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
730             }
731         }, DEFAULT_TIMEOUT_MS);
732 
733         // Make sure we got the expected event.
734         assertNotNull(sixthExpected);
735 
736         // Verify the selection position.
737         assertEquals(1, Selection.getSelectionStart(textView.getText()));
738         assertEquals(1, Selection.getSelectionEnd(textView.getText()));
739 
740         // Move to the previous character and wait for an event.
741         AccessibilityEvent seventhExpected = sUiAutomation
742                 .executeAndWaitForEvent(new Runnable() {
743             @Override
744             public void run() {
745                 text.performAction(
746                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
747             }
748         }, new UiAutomation.AccessibilityEventFilter() {
749             @Override
750             public boolean accept(AccessibilityEvent event) {
751                 return
752                 (event.getEventType() ==
753                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
754                         && event.getAction() ==
755                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
756                         && event.getPackageName().equals(mActivity.getPackageName())
757                         && event.getClassName().equals(TextView.class.getName())
758                         && event.getText().size() > 0
759                         && event.getText().get(0).toString().equals(getString(R.string.a_b))
760                         && event.getFromIndex() == 0
761                         && event.getToIndex() == 1
762                         && event.getMovementGranularity() ==
763                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
764             }
765         }, DEFAULT_TIMEOUT_MS);
766 
767         // Make sure we got the expected event.
768         assertNotNull(seventhExpected);
769 
770         // Verify the selection position.
771         assertEquals(0, Selection.getSelectionStart(textView.getText()));
772         assertEquals(0, Selection.getSelectionEnd(textView.getText()));
773 
774         // Make sure there is no previous.
775         assertFalse(text.performAction(
776                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
777 
778         // Verify the selection position.
779         assertEquals(0, Selection.getSelectionStart(textView.getText()));
780         assertEquals(0, Selection.getSelectionEnd(textView.getText()));
781     }
782 
783     @MediumTest
784     @Test
testActionNextAndPreviousAtGranularityCharacterOverTextExtend()785     public void testActionNextAndPreviousAtGranularityCharacterOverTextExtend()
786             throws Exception {
787         final EditText editText = (EditText) mActivity.findViewById(R.id.edit);
788 
789         sInstrumentation.runOnMainSync(new Runnable() {
790             @Override
791             public void run() {
792                 editText.setVisibility(View.VISIBLE);
793                 editText.setText(getString(R.string.a_b));
794                 Selection.removeSelection(editText.getText());
795             }
796         });
797 
798         final AccessibilityNodeInfo text = sUiAutomation
799                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
800                        getString(R.string.a_b)).get(0);
801 
802         final int granularities = text.getMovementGranularities();
803         assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
804                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
805                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
806                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
807                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
808 
809         final Bundle arguments = new Bundle();
810         arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
811                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
812         arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, true);
813 
814         // Move to the next character and wait for an event.
815         AccessibilityEvent firstExpected = sUiAutomation
816                 .executeAndWaitForEvent(new Runnable() {
817             @Override
818             public void run() {
819                 text.performAction(
820                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
821             }
822         }, new UiAutomation.AccessibilityEventFilter() {
823             @Override
824             public boolean accept(AccessibilityEvent event) {
825                 return
826                 (event.getEventType() ==
827                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
828                         && event.getAction() ==
829                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
830                         && event.getPackageName().equals(mActivity.getPackageName())
831                         && event.getClassName().equals(EditText.class.getName())
832                         && event.getText().size() > 0
833                         && event.getText().get(0).toString().equals(getString(R.string.a_b))
834                         && event.getFromIndex() == 0
835                         && event.getToIndex() == 1
836                         && event.getMovementGranularity() ==
837                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
838             }
839         }, DEFAULT_TIMEOUT_MS);
840 
841         // Make sure we got the expected event.
842         assertNotNull(firstExpected);
843 
844         // Verify the selection position.
845         assertEquals(0, Selection.getSelectionStart(editText.getText()));
846         assertEquals(1, Selection.getSelectionEnd(editText.getText()));
847 
848         // Move to the next character and wait for an event.
849         AccessibilityEvent secondExpected = sUiAutomation
850                 .executeAndWaitForEvent(new Runnable() {
851             @Override
852             public void run() {
853                 text.performAction(
854                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
855             }
856         }, new UiAutomation.AccessibilityEventFilter() {
857             @Override
858             public boolean accept(AccessibilityEvent event) {
859                 return
860                 (event.getEventType() ==
861                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
862                         && event.getAction() ==
863                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
864                         && event.getPackageName().equals(mActivity.getPackageName())
865                         && event.getClassName().equals(EditText.class.getName())
866                         && event.getText().size() > 0
867                         && event.getText().get(0).toString().equals(getString(R.string.a_b))
868                         && event.getFromIndex() == 1
869                         && event.getToIndex() == 2
870                         && event.getMovementGranularity() ==
871                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
872             }
873         }, DEFAULT_TIMEOUT_MS);
874 
875         // Make sure we got the expected event.
876         assertNotNull(secondExpected);
877 
878         // Verify the selection position.
879         assertEquals(0, Selection.getSelectionStart(editText.getText()));
880         assertEquals(2, Selection.getSelectionEnd(editText.getText()));
881 
882         // Move to the next character and wait for an event.
883         AccessibilityEvent thirdExpected = sUiAutomation
884                 .executeAndWaitForEvent(new Runnable() {
885             @Override
886             public void run() {
887                 text.performAction(
888                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
889             }
890         }, new UiAutomation.AccessibilityEventFilter() {
891             @Override
892             public boolean accept(AccessibilityEvent event) {
893                 return
894                 (event.getEventType() ==
895                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
896                         && event.getAction() ==
897                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
898                         && event.getPackageName().equals(mActivity.getPackageName())
899                         && event.getClassName().equals(EditText.class.getName())
900                         && event.getText().size() > 0
901                         && event.getText().get(0).toString().equals(getString(R.string.a_b))
902                         && event.getFromIndex() == 2
903                         && event.getToIndex() == 3
904                         && event.getMovementGranularity() ==
905                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
906             }
907         }, DEFAULT_TIMEOUT_MS);
908 
909         // Make sure we got the expected event.
910         assertNotNull(thirdExpected);
911 
912         // Verify the selection position.
913         assertEquals(0, Selection.getSelectionStart(editText.getText()));
914         assertEquals(3, Selection.getSelectionEnd(editText.getText()));
915 
916         // Make sure there is no next.
917         assertFalse(text.performAction(
918                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
919 
920         // Verify the selection position.
921         assertEquals(0, Selection.getSelectionStart(editText.getText()));
922         assertEquals(3, Selection.getSelectionEnd(editText.getText()));
923 
924         // Move to the previous character and wait for an event.
925         AccessibilityEvent fourthExpected = sUiAutomation
926                 .executeAndWaitForEvent(new Runnable() {
927             @Override
928             public void run() {
929                 text.performAction(
930                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
931             }
932         }, new UiAutomation.AccessibilityEventFilter() {
933             @Override
934             public boolean accept(AccessibilityEvent event) {
935                 return
936                 (event.getEventType() ==
937                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
938                         && event.getAction() ==
939                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
940                         && event.getPackageName().equals(mActivity.getPackageName())
941                         && event.getClassName().equals(EditText.class.getName())
942                         && event.getText().size() > 0
943                         && event.getText().get(0).toString().equals(getString(R.string.a_b))
944                         && event.getFromIndex() == 2
945                         && event.getToIndex() == 3
946                         && event.getMovementGranularity() ==
947                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
948             }
949         }, DEFAULT_TIMEOUT_MS);
950 
951         // Make sure we got the expected event.
952         assertNotNull(fourthExpected);
953 
954         // Verify the selection position.
955         assertEquals(0, Selection.getSelectionStart(editText.getText()));
956         assertEquals(2, Selection.getSelectionEnd(editText.getText()));
957 
958         // Move to the previous character and wait for an event.
959         AccessibilityEvent fifthExpected = sUiAutomation
960                 .executeAndWaitForEvent(new Runnable() {
961             @Override
962             public void run() {
963                 text.performAction(
964                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
965             }
966         }, new UiAutomation.AccessibilityEventFilter() {
967             @Override
968             public boolean accept(AccessibilityEvent event) {
969                 return
970                 (event.getEventType() ==
971                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
972                         && event.getAction() ==
973                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
974                         && event.getPackageName().equals(mActivity.getPackageName())
975                         && event.getClassName().equals(EditText.class.getName())
976                         && event.getText().size() > 0
977                         && event.getText().get(0).toString().equals(getString(R.string.a_b))
978                         && event.getFromIndex() == 1
979                         && event.getToIndex() == 2
980                         && event.getMovementGranularity() ==
981                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
982             }
983         }, DEFAULT_TIMEOUT_MS);
984 
985         // Make sure we got the expected event.
986         assertNotNull(fifthExpected);
987 
988         // Verify the selection position.
989         assertEquals(0, Selection.getSelectionStart(editText.getText()));
990         assertEquals(1, Selection.getSelectionEnd(editText.getText()));
991 
992         // Move to the previous character and wait for an event.
993         AccessibilityEvent sixthExpected = sUiAutomation
994                 .executeAndWaitForEvent(new Runnable() {
995             @Override
996             public void run() {
997                 text.performAction(
998                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
999             }
1000         }, new UiAutomation.AccessibilityEventFilter() {
1001             @Override
1002             public boolean accept(AccessibilityEvent event) {
1003                 return
1004                 (event.getEventType() ==
1005                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
1006                         && event.getAction() ==
1007                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
1008                         && event.getPackageName().equals(mActivity.getPackageName())
1009                         && event.getClassName().equals(EditText.class.getName())
1010                         && event.getText().size() > 0
1011                         && event.getText().get(0).toString().equals(getString(R.string.a_b))
1012                         && event.getFromIndex() == 0
1013                         && event.getToIndex() == 1
1014                         && event.getMovementGranularity() ==
1015                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
1016             }
1017         }, DEFAULT_TIMEOUT_MS);
1018 
1019         // Make sure we got the expected event.
1020         assertNotNull(sixthExpected);
1021 
1022         // Verify the selection position.
1023         assertEquals(0, Selection.getSelectionStart(editText.getText()));
1024         assertEquals(0, Selection.getSelectionEnd(editText.getText()));
1025 
1026         // Make sure there is no previous.
1027         assertFalse(text.performAction(
1028                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
1029 
1030         // Verify the selection position.
1031         assertEquals(0, Selection.getSelectionStart(editText.getText()));
1032         assertEquals(0, Selection.getSelectionEnd(editText.getText()));
1033 
1034         // Focus the view so we can change selection.
1035         sInstrumentation.runOnMainSync(new Runnable() {
1036             @Override
1037             public void run() {
1038                 editText.setFocusable(true);
1039                 editText.requestFocus();
1040             }
1041         });
1042 
1043         // Put selection at the end of the text.
1044         Bundle setSelectionArgs = new Bundle();
1045         setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 3);
1046         setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 3);
1047         assertTrue(text.performAction(
1048                 AccessibilityNodeInfo.ACTION_SET_SELECTION, setSelectionArgs));
1049 
1050         // Verify the selection position.
1051         assertEquals(3, Selection.getSelectionStart(editText.getText()));
1052         assertEquals(3, Selection.getSelectionEnd(editText.getText()));
1053 
1054         // Move to the previous character and wait for an event.
1055         AccessibilityEvent seventhExpected = sUiAutomation
1056                 .executeAndWaitForEvent(new Runnable() {
1057             @Override
1058             public void run() {
1059                 text.performAction(
1060                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
1061             }
1062         }, new UiAutomation.AccessibilityEventFilter() {
1063             @Override
1064             public boolean accept(AccessibilityEvent event) {
1065                 return
1066                 (event.getEventType() ==
1067                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
1068                         && event.getAction() ==
1069                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
1070                         && event.getPackageName().equals(mActivity.getPackageName())
1071                         && event.getClassName().equals(EditText.class.getName())
1072                         && event.getText().size() > 0
1073                         && event.getText().get(0).toString().equals(getString(R.string.a_b))
1074                         && event.getFromIndex() == 2
1075                         && event.getToIndex() == 3
1076                         && event.getMovementGranularity() ==
1077                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
1078             }
1079         }, DEFAULT_TIMEOUT_MS);
1080 
1081         // Make sure we got the expected event.
1082         assertNotNull(seventhExpected);
1083 
1084         // Verify the selection position.
1085         assertEquals(3, Selection.getSelectionStart(editText.getText()));
1086         assertEquals(2, Selection.getSelectionEnd(editText.getText()));
1087 
1088         // Move to the previous character and wait for an event.
1089         AccessibilityEvent eightExpected = sUiAutomation
1090                 .executeAndWaitForEvent(new Runnable() {
1091             @Override
1092             public void run() {
1093                 text.performAction(
1094                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
1095             }
1096         }, new UiAutomation.AccessibilityEventFilter() {
1097             @Override
1098             public boolean accept(AccessibilityEvent event) {
1099                 return
1100                 (event.getEventType() ==
1101                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
1102                         && event.getAction() ==
1103                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
1104                         && event.getPackageName().equals(mActivity.getPackageName())
1105                         && event.getClassName().equals(EditText.class.getName())
1106                         && event.getText().size() > 0
1107                         && event.getText().get(0).toString().equals(getString(R.string.a_b))
1108                         && event.getFromIndex() == 1
1109                         && event.getToIndex() == 2
1110                         && event.getMovementGranularity() ==
1111                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
1112             }
1113         }, DEFAULT_TIMEOUT_MS);
1114 
1115         // Make sure we got the expected event.
1116         assertNotNull(eightExpected);
1117 
1118         // Verify the selection position.
1119         assertEquals(3, Selection.getSelectionStart(editText.getText()));
1120         assertEquals(1, Selection.getSelectionEnd(editText.getText()));
1121 
1122         // Move to the previous character and wait for an event.
1123         AccessibilityEvent ninethExpected = sUiAutomation
1124                 .executeAndWaitForEvent(new Runnable() {
1125             @Override
1126             public void run() {
1127                 text.performAction(
1128                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
1129             }
1130         }, new UiAutomation.AccessibilityEventFilter() {
1131             @Override
1132             public boolean accept(AccessibilityEvent event) {
1133                 return
1134                 (event.getEventType() ==
1135                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
1136                         && event.getAction() ==
1137                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
1138                         && event.getPackageName().equals(mActivity.getPackageName())
1139                         && event.getClassName().equals(EditText.class.getName())
1140                         && event.getText().size() > 0
1141                         && event.getText().get(0).toString().equals(getString(R.string.a_b))
1142                         && event.getFromIndex() == 0
1143                         && event.getToIndex() == 1
1144                         && event.getMovementGranularity() ==
1145                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
1146             }
1147         }, DEFAULT_TIMEOUT_MS);
1148 
1149         // Make sure we got the expected event.
1150         assertNotNull(ninethExpected);
1151 
1152         // Verify the selection position.
1153         assertEquals(3, Selection.getSelectionStart(editText.getText()));
1154         assertEquals(0, Selection.getSelectionEnd(editText.getText()));
1155 
1156         // Make sure there is no previous.
1157         assertFalse(text.performAction(
1158                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
1159 
1160         // Verify the selection position.
1161         assertEquals(3, Selection.getSelectionStart(editText.getText()));
1162         assertEquals(0, Selection.getSelectionEnd(editText.getText()));
1163 
1164         // Move to the next character and wait for an event.
1165         AccessibilityEvent tenthExpected = sUiAutomation
1166                 .executeAndWaitForEvent(new Runnable() {
1167             @Override
1168             public void run() {
1169                 text.performAction(
1170                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
1171             }
1172         }, new UiAutomation.AccessibilityEventFilter() {
1173             @Override
1174             public boolean accept(AccessibilityEvent event) {
1175                 return
1176                 (event.getEventType() ==
1177                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
1178                         && event.getAction() ==
1179                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
1180                         && event.getPackageName().equals(mActivity.getPackageName())
1181                         && event.getClassName().equals(EditText.class.getName())
1182                         && event.getText().size() > 0
1183                         && event.getText().get(0).toString().equals(getString(R.string.a_b))
1184                         && event.getFromIndex() == 0
1185                         && event.getToIndex() == 1
1186                         && event.getMovementGranularity() ==
1187                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
1188             }
1189         }, DEFAULT_TIMEOUT_MS);
1190 
1191         // Make sure we got the expected event.
1192         assertNotNull(tenthExpected);
1193 
1194         // Verify the selection position.
1195         assertEquals(3, Selection.getSelectionStart(editText.getText()));
1196         assertEquals(1, Selection.getSelectionEnd(editText.getText()));
1197 
1198         // Move to the next character and wait for an event.
1199         AccessibilityEvent eleventhExpected = sUiAutomation
1200                 .executeAndWaitForEvent(new Runnable() {
1201             @Override
1202             public void run() {
1203                 text.performAction(
1204                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
1205             }
1206         }, new UiAutomation.AccessibilityEventFilter() {
1207             @Override
1208             public boolean accept(AccessibilityEvent event) {
1209                 return
1210                 (event.getEventType() ==
1211                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
1212                         && event.getAction() ==
1213                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
1214                         && event.getPackageName().equals(mActivity.getPackageName())
1215                         && event.getClassName().equals(EditText.class.getName())
1216                         && event.getText().size() > 0
1217                         && event.getText().get(0).toString().equals(getString(R.string.a_b))
1218                         && event.getFromIndex() == 1
1219                         && event.getToIndex() == 2
1220                         && event.getMovementGranularity() ==
1221                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
1222             }
1223         }, DEFAULT_TIMEOUT_MS);
1224 
1225         // Make sure we got the expected event.
1226         assertNotNull(eleventhExpected);
1227 
1228         // Verify the selection position.
1229         assertEquals(3, Selection.getSelectionStart(editText.getText()));
1230         assertEquals(2, Selection.getSelectionEnd(editText.getText()));
1231 
1232         // Move to the next character and wait for an event.
1233         AccessibilityEvent twelvethExpected = sUiAutomation
1234                 .executeAndWaitForEvent(new Runnable() {
1235             @Override
1236             public void run() {
1237                 text.performAction(
1238                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
1239             }
1240         }, new UiAutomation.AccessibilityEventFilter() {
1241             @Override
1242             public boolean accept(AccessibilityEvent event) {
1243                 return
1244                 (event.getEventType() ==
1245                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
1246                         && event.getAction() ==
1247                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
1248                         && event.getPackageName().equals(mActivity.getPackageName())
1249                         && event.getClassName().equals(EditText.class.getName())
1250                         && event.getText().size() > 0
1251                         && event.getText().get(0).toString().equals(getString(R.string.a_b))
1252                         && event.getFromIndex() == 2
1253                         && event.getToIndex() == 3
1254                         && event.getMovementGranularity() ==
1255                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
1256             }
1257         }, DEFAULT_TIMEOUT_MS);
1258 
1259         // Make sure we got the expected event.
1260         assertNotNull(twelvethExpected);
1261 
1262         // Verify the selection position.
1263         assertEquals(3, Selection.getSelectionStart(editText.getText()));
1264         assertEquals(3, Selection.getSelectionEnd(editText.getText()));
1265 
1266         // Make sure there is no next.
1267         assertFalse(text.performAction(
1268                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
1269 
1270         // Verify the selection position.
1271         assertEquals(3, Selection.getSelectionStart(editText.getText()));
1272         assertEquals(3, Selection.getSelectionEnd(editText.getText()));
1273     }
1274 
1275     @MediumTest
1276     @Test
testActionNextAndPreviousAtGranularityWordOverText()1277     public void testActionNextAndPreviousAtGranularityWordOverText() throws Exception {
1278         final TextView textView = (TextView) mActivity.findViewById(R.id.text);
1279 
1280         sInstrumentation.runOnMainSync(new Runnable() {
1281             @Override
1282             public void run() {
1283                 textView.setVisibility(View.VISIBLE);
1284                 textView.setText(getString(R.string.foo_bar_baz));
1285             }
1286         });
1287 
1288         final AccessibilityNodeInfo text = sUiAutomation
1289                .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
1290                        R.string.foo_bar_baz)).get(0);
1291 
1292         final int granularities = text.getMovementGranularities();
1293         assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
1294                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
1295                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
1296                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
1297                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
1298 
1299         final Bundle arguments = new Bundle();
1300         arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
1301                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
1302 
1303         // Move to the next word and wait for an event.
1304         AccessibilityEvent firstExpected = sUiAutomation
1305                 .executeAndWaitForEvent(new Runnable() {
1306             @Override
1307             public void run() {
1308                 text.performAction(
1309                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
1310             }
1311         }, new UiAutomation.AccessibilityEventFilter() {
1312             @Override
1313             public boolean accept(AccessibilityEvent event) {
1314                 return
1315                 (event.getEventType() ==
1316                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
1317                         && event.getAction() ==
1318                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
1319                         && event.getPackageName().equals(mActivity.getPackageName())
1320                         && event.getClassName().equals(TextView.class.getName())
1321                         && event.getText().size() > 0
1322                         && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
1323                         && event.getFromIndex() == 0
1324                         && event.getToIndex() == 3
1325                         && event.getMovementGranularity() ==
1326                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
1327             }
1328         }, DEFAULT_TIMEOUT_MS);
1329 
1330         // Make sure we got the expected event.
1331         assertNotNull(firstExpected);
1332 
1333         // Verify the selection position.
1334         assertEquals(3, Selection.getSelectionStart(textView.getText()));
1335         assertEquals(3, Selection.getSelectionEnd(textView.getText()));
1336 
1337         // Move to the next word and wait for an event.
1338         AccessibilityEvent secondExpected = sUiAutomation
1339                 .executeAndWaitForEvent(new Runnable() {
1340             @Override
1341             public void run() {
1342                 text.performAction(
1343                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
1344             }
1345         }, new UiAutomation.AccessibilityEventFilter() {
1346             @Override
1347             public boolean accept(AccessibilityEvent event) {
1348                 return
1349                 (event.getEventType() ==
1350                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
1351                         && event.getAction() ==
1352                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
1353                         && event.getPackageName().equals(mActivity.getPackageName())
1354                         && event.getClassName().equals(TextView.class.getName())
1355                         && event.getText().size() > 0
1356                         && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
1357                         && event.getFromIndex() == 4
1358                         && event.getToIndex() == 7
1359                         && event.getMovementGranularity() ==
1360                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
1361             }
1362         }, DEFAULT_TIMEOUT_MS);
1363 
1364         // Make sure we got the expected event.
1365         assertNotNull(secondExpected);
1366 
1367         // Verify the selection position.
1368         assertEquals(7, Selection.getSelectionStart(textView.getText()));
1369         assertEquals(7, Selection.getSelectionEnd(textView.getText()));
1370 
1371         // Move to the next word and wait for an event.
1372         AccessibilityEvent thirdExpected = sUiAutomation
1373                 .executeAndWaitForEvent(new Runnable() {
1374             @Override
1375             public void run() {
1376                 text.performAction(
1377                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
1378             }
1379         }, new UiAutomation.AccessibilityEventFilter() {
1380             @Override
1381             public boolean accept(AccessibilityEvent event) {
1382                 return
1383                 (event.getEventType() ==
1384                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
1385                         && event.getAction() ==
1386                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
1387                         && event.getPackageName().equals(mActivity.getPackageName())
1388                         && event.getClassName().equals(TextView.class.getName())
1389                         && event.getText().size() > 0
1390                         && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
1391                         && event.getFromIndex() == 8
1392                         && event.getToIndex() == 11
1393                         && event.getMovementGranularity() ==
1394                                  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
1395             }
1396         }, DEFAULT_TIMEOUT_MS);
1397 
1398         // Make sure we got the expected event.
1399         assertNotNull(thirdExpected);
1400 
1401         // Verify the selection position.
1402         assertEquals(11, Selection.getSelectionStart(textView.getText()));
1403         assertEquals(11, Selection.getSelectionEnd(textView.getText()));
1404 
1405         // Make sure there is no next.
1406         assertFalse(text.performAction(
1407                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
1408 
1409         // Verify the selection position.
1410         assertEquals(11, Selection.getSelectionStart(textView.getText()));
1411         assertEquals(11, Selection.getSelectionEnd(textView.getText()));
1412 
1413         // Move to the next word and wait for an event.
1414         AccessibilityEvent fourthExpected = sUiAutomation
1415                 .executeAndWaitForEvent(new Runnable() {
1416             @Override
1417             public void run() {
1418                 text.performAction(
1419                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
1420             }
1421         }, new UiAutomation.AccessibilityEventFilter() {
1422             @Override
1423             public boolean accept(AccessibilityEvent event) {
1424                 return
1425                 (event.getEventType() ==
1426                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
1427                         && event.getAction() ==
1428                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
1429                         && event.getPackageName().equals(mActivity.getPackageName())
1430                         && event.getClassName().equals(TextView.class.getName())
1431                         && event.getText().size() > 0
1432                         && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
1433                         && event.getFromIndex() == 8
1434                         && event.getToIndex() == 11
1435                         && event.getMovementGranularity() ==
1436                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
1437             }
1438         }, DEFAULT_TIMEOUT_MS);
1439 
1440         // Make sure we got the expected event.
1441         assertNotNull(fourthExpected);
1442 
1443         // Verify the selection position.
1444         assertEquals(8, Selection.getSelectionStart(textView.getText()));
1445         assertEquals(8, Selection.getSelectionEnd(textView.getText()));
1446 
1447         // Move to the next word and wait for an event.
1448         AccessibilityEvent fifthExpected = sUiAutomation
1449                 .executeAndWaitForEvent(new Runnable() {
1450             @Override
1451             public void run() {
1452                 text.performAction(
1453                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
1454             }
1455         }, new UiAutomation.AccessibilityEventFilter() {
1456             @Override
1457             public boolean accept(AccessibilityEvent event) {
1458                 return
1459                 (event.getEventType() ==
1460                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
1461                         && event.getAction() ==
1462                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
1463                         && event.getPackageName().equals(mActivity.getPackageName())
1464                         && event.getClassName().equals(TextView.class.getName())
1465                         && event.getText().size() > 0
1466                         && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
1467                         && event.getFromIndex() == 4
1468                         && event.getToIndex() == 7
1469                         && event.getMovementGranularity() ==
1470                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
1471             }
1472         }, DEFAULT_TIMEOUT_MS);
1473 
1474         // Make sure we got the expected event.
1475         assertNotNull(fifthExpected);
1476 
1477         // Verify the selection position.
1478         assertEquals(4, Selection.getSelectionStart(textView.getText()));
1479         assertEquals(4, Selection.getSelectionEnd(textView.getText()));
1480 
1481         // Move to the next character and wait for an event.
1482         AccessibilityEvent sixthExpected = sUiAutomation
1483                 .executeAndWaitForEvent(new Runnable() {
1484             @Override
1485             public void run() {
1486                 text.performAction(
1487                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
1488             }
1489         }, new UiAutomation.AccessibilityEventFilter() {
1490             @Override
1491             public boolean accept(AccessibilityEvent event) {
1492                 return
1493                 (event.getEventType() ==
1494                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
1495                         && event.getAction() ==
1496                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
1497                         && event.getPackageName().equals(mActivity.getPackageName())
1498                         && event.getClassName().equals(TextView.class.getName())
1499                         && event.getText().size() > 0
1500                         && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
1501                         && event.getFromIndex() == 0
1502                         && event.getToIndex() == 3
1503                         && event.getMovementGranularity() ==
1504                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
1505             }
1506         }, DEFAULT_TIMEOUT_MS);
1507 
1508         // Make sure we got the expected event.
1509         assertNotNull(sixthExpected);
1510 
1511         // Verify the selection position.
1512         assertEquals(0, Selection.getSelectionStart(textView.getText()));
1513         assertEquals(0, Selection.getSelectionEnd(textView.getText()));
1514 
1515         // Make sure there is no previous.
1516         assertFalse(text.performAction(
1517                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
1518 
1519         // Verify the selection position.
1520         assertEquals(0, Selection.getSelectionStart(textView.getText()));
1521         assertEquals(0, Selection.getSelectionEnd(textView.getText()));
1522     }
1523 
1524     @MediumTest
1525     @Test
testActionNextAndPreviousAtGranularityWordOverEditTextWithContentDescription()1526     public void testActionNextAndPreviousAtGranularityWordOverEditTextWithContentDescription()
1527             throws Exception {
1528         final EditText editText = (EditText) mActivity.findViewById(R.id.edit);
1529 
1530         sInstrumentation.runOnMainSync(new Runnable() {
1531             @Override
1532             public void run() {
1533                 editText.setVisibility(View.VISIBLE);
1534                 editText.setText(getString(R.string.foo_bar_baz));
1535                 editText.setContentDescription(getString(R.string.android_wiki));
1536             }
1537         });
1538 
1539         final AccessibilityNodeInfo text = sUiAutomation
1540                .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
1541                        R.string.foo_bar_baz)).get(0);
1542 
1543         final int granularities = text.getMovementGranularities();
1544         assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
1545                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
1546                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
1547                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
1548                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
1549 
1550         final Bundle arguments = new Bundle();
1551         arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
1552                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
1553 
1554         // Move to the next word and wait for an event.
1555         AccessibilityEvent firstExpected = sUiAutomation
1556                 .executeAndWaitForEvent(new Runnable() {
1557             @Override
1558             public void run() {
1559                 text.performAction(
1560                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
1561             }
1562         }, new UiAutomation.AccessibilityEventFilter() {
1563             @Override
1564             public boolean accept(AccessibilityEvent event) {
1565                 return
1566                 (event.getEventType() ==
1567                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
1568                         && event.getAction() ==
1569                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
1570                         && event.getPackageName().equals(mActivity.getPackageName())
1571                         && event.getClassName().equals(EditText.class.getName())
1572                         && event.getText().size() > 0
1573                         && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
1574                         && event.getContentDescription().equals(getString(R.string.android_wiki))
1575                         && event.getFromIndex() == 0
1576                         && event.getToIndex() == 3
1577                         && event.getMovementGranularity() ==
1578                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
1579             }
1580         }, DEFAULT_TIMEOUT_MS);
1581 
1582         // Make sure we got the expected event.
1583         assertNotNull(firstExpected);
1584 
1585         // Verify the selection position.
1586         assertEquals(3, editText.getSelectionStart());
1587         assertEquals(3, editText.getSelectionEnd());
1588 
1589         // Move to the next word and wait for an event.
1590         AccessibilityEvent secondExpected = sUiAutomation
1591                 .executeAndWaitForEvent(new Runnable() {
1592             @Override
1593             public void run() {
1594                 text.performAction(
1595                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
1596             }
1597         }, new UiAutomation.AccessibilityEventFilter() {
1598             @Override
1599             public boolean accept(AccessibilityEvent event) {
1600                 return
1601                 (event.getEventType() ==
1602                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
1603                         && event.getAction() ==
1604                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
1605                         && event.getPackageName().equals(mActivity.getPackageName())
1606                         && event.getClassName().equals(EditText.class.getName())
1607                         && event.getText().size() > 0
1608                         && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
1609                         && event.getContentDescription().equals(getString(R.string.android_wiki))
1610                         && event.getFromIndex() == 4
1611                         && event.getToIndex() == 7
1612                         && event.getMovementGranularity() ==
1613                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
1614             }
1615         }, DEFAULT_TIMEOUT_MS);
1616 
1617         // Make sure we got the expected event.
1618         assertNotNull(secondExpected);
1619 
1620         // Verify the selection position.
1621         assertEquals(7, editText.getSelectionStart());
1622         assertEquals(7, editText.getSelectionEnd());
1623 
1624         // Move to the next word and wait for an event.
1625         AccessibilityEvent thirdExpected = sUiAutomation
1626                 .executeAndWaitForEvent(new Runnable() {
1627             @Override
1628             public void run() {
1629                 text.performAction(
1630                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
1631             }
1632         }, new UiAutomation.AccessibilityEventFilter() {
1633             @Override
1634             public boolean accept(AccessibilityEvent event) {
1635                 return
1636                 (event.getEventType() ==
1637                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
1638                         && event.getAction() ==
1639                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
1640                         && event.getPackageName().equals(mActivity.getPackageName())
1641                         && event.getClassName().equals(EditText.class.getName())
1642                         && event.getText().size() > 0
1643                         && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
1644                         && event.getContentDescription().equals(getString(R.string.android_wiki))
1645                         && event.getFromIndex() == 8
1646                         && event.getToIndex() == 11
1647                         && event.getMovementGranularity() ==
1648                                  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
1649             }
1650         }, DEFAULT_TIMEOUT_MS);
1651 
1652         // Make sure we got the expected event.
1653         assertNotNull(thirdExpected);
1654 
1655         // Verify the selection position.
1656         assertEquals(11, editText.getSelectionStart());
1657         assertEquals(11, editText.getSelectionEnd());
1658 
1659         // Make sure there is no next.
1660         assertFalse(text.performAction(
1661                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
1662 
1663         // Verify the selection position.
1664         assertEquals(11, editText.getSelectionStart());
1665         assertEquals(11, editText.getSelectionEnd());
1666 
1667         // Move to the next word and wait for an event.
1668         AccessibilityEvent fourthExpected = sUiAutomation
1669                 .executeAndWaitForEvent(new Runnable() {
1670             @Override
1671             public void run() {
1672                 text.performAction(
1673                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
1674             }
1675         }, new UiAutomation.AccessibilityEventFilter() {
1676             @Override
1677             public boolean accept(AccessibilityEvent event) {
1678                 return
1679                 (event.getEventType() ==
1680                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
1681                         && event.getAction() ==
1682                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
1683                         && event.getPackageName().equals(mActivity.getPackageName())
1684                         && event.getClassName().equals(EditText.class.getName())
1685                         && event.getText().size() > 0
1686                         && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
1687                         && event.getContentDescription().equals(getString(R.string.android_wiki))
1688                         && event.getFromIndex() == 8
1689                         && event.getToIndex() == 11
1690                         && event.getMovementGranularity() ==
1691                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
1692             }
1693         }, DEFAULT_TIMEOUT_MS);
1694 
1695         // Make sure we got the expected event.
1696         assertNotNull(fourthExpected);
1697 
1698         // Verify the selection position.
1699         assertEquals(8, editText.getSelectionStart());
1700         assertEquals(8, editText.getSelectionEnd());
1701 
1702         // Move to the next word and wait for an event.
1703         AccessibilityEvent fifthExpected = sUiAutomation
1704                 .executeAndWaitForEvent(new Runnable() {
1705             @Override
1706             public void run() {
1707                 text.performAction(
1708                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
1709             }
1710         }, new UiAutomation.AccessibilityEventFilter() {
1711             @Override
1712             public boolean accept(AccessibilityEvent event) {
1713                 return
1714                 (event.getEventType() ==
1715                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
1716                         && event.getAction() ==
1717                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
1718                         && event.getPackageName().equals(mActivity.getPackageName())
1719                         && event.getClassName().equals(EditText.class.getName())
1720                         && event.getText().size() > 0
1721                         && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
1722                         && event.getContentDescription().equals(getString(R.string.android_wiki))
1723                         && event.getFromIndex() == 4
1724                         && event.getToIndex() == 7
1725                         && event.getMovementGranularity() ==
1726                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
1727             }
1728         }, DEFAULT_TIMEOUT_MS);
1729 
1730         // Make sure we got the expected event.
1731         assertNotNull(fifthExpected);
1732 
1733         // Verify the selection position.
1734         assertEquals(4, editText.getSelectionStart());
1735         assertEquals(4, editText.getSelectionEnd());
1736 
1737         // Move to the next character and wait for an event.
1738         AccessibilityEvent sixthExpected = sUiAutomation
1739                 .executeAndWaitForEvent(new Runnable() {
1740             @Override
1741             public void run() {
1742                 text.performAction(
1743                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
1744             }
1745         }, new UiAutomation.AccessibilityEventFilter() {
1746             @Override
1747             public boolean accept(AccessibilityEvent event) {
1748                 return
1749                 (event.getEventType() ==
1750                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
1751                         && event.getAction() ==
1752                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
1753                         && event.getPackageName().equals(mActivity.getPackageName())
1754                         && event.getClassName().equals(EditText.class.getName())
1755                         && event.getText().size() > 0
1756                         && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
1757                         && event.getContentDescription().equals(getString(R.string.android_wiki))
1758                         && event.getFromIndex() == 0
1759                         && event.getToIndex() == 3
1760                         && event.getMovementGranularity() ==
1761                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
1762             }
1763         }, DEFAULT_TIMEOUT_MS);
1764 
1765         // Make sure we got the expected event.
1766         assertNotNull(sixthExpected);
1767 
1768         // Verify the selection position.
1769         assertEquals(0, editText.getSelectionStart());
1770         assertEquals(0, editText.getSelectionEnd());
1771 
1772         // Make sure there is no previous.
1773         assertFalse(text.performAction(
1774                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
1775 
1776         // Verify the selection position.
1777         assertEquals(0, editText.getSelectionStart());
1778         assertEquals(0, editText.getSelectionEnd());
1779     }
1780 
1781     @MediumTest
1782     @Test
testActionNextAndPreviousAtGranularityWordOverTextExtend()1783     public void testActionNextAndPreviousAtGranularityWordOverTextExtend() throws Exception {
1784         final EditText editText = (EditText) mActivity.findViewById(R.id.edit);
1785 
1786         sInstrumentation.runOnMainSync(new Runnable() {
1787             @Override
1788             public void run() {
1789                 editText.setVisibility(View.VISIBLE);
1790                 editText.setText(getString(R.string.foo_bar_baz));
1791                 Selection.removeSelection(editText.getText());
1792             }
1793         });
1794 
1795         final AccessibilityNodeInfo text = sUiAutomation
1796                .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
1797                        R.string.foo_bar_baz)).get(0);
1798 
1799         final int granularities = text.getMovementGranularities();
1800         assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
1801                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
1802                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
1803                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
1804                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
1805 
1806         final Bundle arguments = new Bundle();
1807         arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
1808                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
1809         arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, true);
1810 
1811         // Move to the next word and wait for an event.
1812         AccessibilityEvent firstExpected = sUiAutomation
1813                 .executeAndWaitForEvent(new Runnable() {
1814             @Override
1815             public void run() {
1816                 text.performAction(
1817                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
1818             }
1819         }, new UiAutomation.AccessibilityEventFilter() {
1820             @Override
1821             public boolean accept(AccessibilityEvent event) {
1822                 return
1823                 (event.getEventType() ==
1824                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
1825                         && event.getAction() ==
1826                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
1827                         && event.getPackageName().equals(mActivity.getPackageName())
1828                         && event.getClassName().equals(EditText.class.getName())
1829                         && event.getText().size() > 0
1830                         && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
1831                         && event.getFromIndex() == 0
1832                         && event.getToIndex() == 3
1833                         && event.getMovementGranularity() ==
1834                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
1835             }
1836         }, DEFAULT_TIMEOUT_MS);
1837 
1838         // Make sure we got the expected event.
1839         assertNotNull(firstExpected);
1840 
1841         // Verify the selection position.
1842         assertEquals(0, Selection.getSelectionStart(editText.getText()));
1843         assertEquals(3, Selection.getSelectionEnd(editText.getText()));
1844 
1845         // Move to the next word and wait for an event.
1846         AccessibilityEvent secondExpected = sUiAutomation
1847                 .executeAndWaitForEvent(new Runnable() {
1848             @Override
1849             public void run() {
1850                 text.performAction(
1851                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
1852             }
1853         }, new UiAutomation.AccessibilityEventFilter() {
1854             @Override
1855             public boolean accept(AccessibilityEvent event) {
1856                 return
1857                 (event.getEventType() ==
1858                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
1859                         && event.getAction() ==
1860                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
1861                         && event.getPackageName().equals(mActivity.getPackageName())
1862                         && event.getClassName().equals(EditText.class.getName())
1863                         && event.getText().size() > 0
1864                         && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
1865                         && event.getFromIndex() == 4
1866                         && event.getToIndex() == 7
1867                         && event.getMovementGranularity() ==
1868                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
1869             }
1870         }, DEFAULT_TIMEOUT_MS);
1871 
1872         // Make sure we got the expected event.
1873         assertNotNull(secondExpected);
1874 
1875         // Verify the selection position.
1876         assertEquals(0, Selection.getSelectionStart(editText.getText()));
1877         assertEquals(7, Selection.getSelectionEnd(editText.getText()));
1878 
1879         // Move to the next word and wait for an event.
1880         AccessibilityEvent thirdExpected = sUiAutomation
1881                 .executeAndWaitForEvent(new Runnable() {
1882             @Override
1883             public void run() {
1884                 text.performAction(
1885                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
1886             }
1887         }, new UiAutomation.AccessibilityEventFilter() {
1888             @Override
1889             public boolean accept(AccessibilityEvent event) {
1890                 return
1891                 (event.getEventType() ==
1892                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
1893                         && event.getAction() ==
1894                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
1895                         && event.getPackageName().equals(mActivity.getPackageName())
1896                         && event.getClassName().equals(EditText.class.getName())
1897                         && event.getText().size() > 0
1898                         && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
1899                         && event.getFromIndex() == 8
1900                         && event.getToIndex() == 11
1901                         && event.getMovementGranularity() ==
1902                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
1903             }
1904         }, DEFAULT_TIMEOUT_MS);
1905 
1906         // Make sure we got the expected event.
1907         assertNotNull(thirdExpected);
1908 
1909         // Verify the selection position.
1910         assertEquals(0, Selection.getSelectionStart(editText.getText()));
1911         assertEquals(11, Selection.getSelectionEnd(editText.getText()));
1912 
1913         // Make sure there is no next.
1914         assertFalse(text.performAction(
1915                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
1916 
1917         // Move to the previous word and wait for an event.
1918         AccessibilityEvent fourthExpected = sUiAutomation
1919                 .executeAndWaitForEvent(new Runnable() {
1920             @Override
1921             public void run() {
1922                 text.performAction(
1923                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
1924             }
1925         }, new UiAutomation.AccessibilityEventFilter() {
1926             @Override
1927             public boolean accept(AccessibilityEvent event) {
1928                 return
1929                 (event.getEventType() ==
1930                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
1931                         && event.getAction() ==
1932                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
1933                         && event.getPackageName().equals(mActivity.getPackageName())
1934                         && event.getClassName().equals(EditText.class.getName())
1935                         && event.getText().size() > 0
1936                         && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
1937                         && event.getFromIndex() == 8
1938                         && event.getToIndex() == 11
1939                         && event.getMovementGranularity() ==
1940                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
1941             }
1942         }, DEFAULT_TIMEOUT_MS);
1943 
1944         // Make sure we got the expected event.
1945         assertNotNull(fourthExpected);
1946 
1947         // Verify the selection position.
1948         assertEquals(0, Selection.getSelectionStart(editText.getText()));
1949         assertEquals(8, Selection.getSelectionEnd(editText.getText()));
1950 
1951         // Move to the previous word and wait for an event.
1952         AccessibilityEvent fifthExpected = sUiAutomation
1953                 .executeAndWaitForEvent(new Runnable() {
1954             @Override
1955             public void run() {
1956                 text.performAction(
1957                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
1958             }
1959         }, new UiAutomation.AccessibilityEventFilter() {
1960             @Override
1961             public boolean accept(AccessibilityEvent event) {
1962                 return
1963                 (event.getEventType() ==
1964                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
1965                         && event.getAction() ==
1966                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
1967                         && event.getPackageName().equals(mActivity.getPackageName())
1968                         && event.getClassName().equals(EditText.class.getName())
1969                         && event.getText().size() > 0
1970                         && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
1971                         && event.getFromIndex() == 4
1972                         && event.getToIndex() == 7
1973                         && event.getMovementGranularity() ==
1974                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
1975             }
1976         }, DEFAULT_TIMEOUT_MS);
1977 
1978         // Make sure we got the expected event.
1979         assertNotNull(fifthExpected);
1980 
1981         // Verify the selection position.
1982         assertEquals(0, Selection.getSelectionStart(editText.getText()));
1983         assertEquals(4, Selection.getSelectionEnd(editText.getText()));
1984 
1985         // Move to the previous character and wait for an event.
1986         AccessibilityEvent sixthExpected = sUiAutomation
1987                 .executeAndWaitForEvent(new Runnable() {
1988             @Override
1989             public void run() {
1990                 text.performAction(
1991                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
1992             }
1993         }, new UiAutomation.AccessibilityEventFilter() {
1994             @Override
1995             public boolean accept(AccessibilityEvent event) {
1996                 return
1997                 (event.getEventType() ==
1998                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
1999                         && event.getAction() ==
2000                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
2001                         && event.getPackageName().equals(mActivity.getPackageName())
2002                         && event.getClassName().equals(EditText.class.getName())
2003                         && event.getText().size() > 0
2004                         && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
2005                         && event.getFromIndex() == 0
2006                         && event.getToIndex() == 3
2007                         && event.getMovementGranularity() ==
2008                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
2009             }
2010         }, DEFAULT_TIMEOUT_MS);
2011 
2012         // Make sure we got the expected event.
2013         assertNotNull(sixthExpected);
2014 
2015         // Verify the selection position.
2016         assertEquals(0, Selection.getSelectionStart(editText.getText()));
2017         assertEquals(0, Selection.getSelectionEnd(editText.getText()));
2018 
2019         // Make sure there is no previous.
2020         assertFalse(text.performAction(
2021                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
2022 
2023         // Verify the selection position.
2024         assertEquals(0, Selection.getSelectionStart(editText.getText()));
2025         assertEquals(0, Selection.getSelectionEnd(editText.getText()));
2026 
2027         // Focus the view so we can change selection.
2028         sInstrumentation.runOnMainSync(new Runnable() {
2029             @Override
2030             public void run() {
2031                 editText.setFocusable(true);
2032                 editText.requestFocus();
2033             }
2034         });
2035 
2036         // Put selection at the end of the text.
2037         Bundle setSelectionArgs = new Bundle();
2038         setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 11);
2039         setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 11);
2040         assertTrue(text.performAction(
2041                 AccessibilityNodeInfo.ACTION_SET_SELECTION, setSelectionArgs));
2042 
2043         // Verify the selection position.
2044         assertEquals(11, Selection.getSelectionStart(editText.getText()));
2045         assertEquals(11, Selection.getSelectionEnd(editText.getText()));
2046 
2047         // Move to the previous word and wait for an event.
2048         AccessibilityEvent seventhExpected = sUiAutomation
2049                 .executeAndWaitForEvent(new Runnable() {
2050             @Override
2051             public void run() {
2052                 text.performAction(
2053                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
2054             }
2055         }, new UiAutomation.AccessibilityEventFilter() {
2056             @Override
2057             public boolean accept(AccessibilityEvent event) {
2058                 return
2059                 (event.getEventType() ==
2060                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
2061                         && event.getAction() ==
2062                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
2063                         && event.getPackageName().equals(mActivity.getPackageName())
2064                         && event.getClassName().equals(EditText.class.getName())
2065                         && event.getText().size() > 0
2066                         && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
2067                         && event.getFromIndex() == 8
2068                         && event.getToIndex() == 11
2069                         && event.getMovementGranularity() ==
2070                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
2071             }
2072         }, DEFAULT_TIMEOUT_MS);
2073 
2074         // Make sure we got the expected event.
2075         assertNotNull(seventhExpected);
2076 
2077         // Verify the selection position.
2078         assertEquals(11, Selection.getSelectionStart(editText.getText()));
2079         assertEquals(8, Selection.getSelectionEnd(editText.getText()));
2080 
2081         // Move to the previous word and wait for an event.
2082         AccessibilityEvent eightExpected = sUiAutomation
2083                 .executeAndWaitForEvent(new Runnable() {
2084             @Override
2085             public void run() {
2086                 text.performAction(
2087                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
2088             }
2089         }, new UiAutomation.AccessibilityEventFilter() {
2090             @Override
2091             public boolean accept(AccessibilityEvent event) {
2092                 return
2093                 (event.getEventType() ==
2094                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
2095                         && event.getAction() ==
2096                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
2097                         && event.getPackageName().equals(mActivity.getPackageName())
2098                         && event.getClassName().equals(EditText.class.getName())
2099                         && event.getText().size() > 0
2100                         && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
2101                         && event.getFromIndex() == 4
2102                         && event.getToIndex() == 7
2103                         && event.getMovementGranularity() ==
2104                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
2105             }
2106         }, DEFAULT_TIMEOUT_MS);
2107 
2108         // Make sure we got the expected event.
2109         assertNotNull(eightExpected);
2110 
2111         // Verify the selection position.
2112         assertEquals(11, Selection.getSelectionStart(editText.getText()));
2113         assertEquals(4, Selection.getSelectionEnd(editText.getText()));
2114 
2115         // Move to the previous character and wait for an event.
2116         AccessibilityEvent ninethExpected = sUiAutomation
2117                 .executeAndWaitForEvent(new Runnable() {
2118             @Override
2119             public void run() {
2120                 text.performAction(
2121                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
2122             }
2123         }, new UiAutomation.AccessibilityEventFilter() {
2124             @Override
2125             public boolean accept(AccessibilityEvent event) {
2126                 return
2127                 (event.getEventType() ==
2128                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
2129                         && event.getAction() ==
2130                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
2131                         && event.getPackageName().equals(mActivity.getPackageName())
2132                         && event.getClassName().equals(EditText.class.getName())
2133                         && event.getText().size() > 0
2134                         && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
2135                         && event.getFromIndex() == 0
2136                         && event.getToIndex() == 3
2137                         && event.getMovementGranularity() ==
2138                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
2139             }
2140         }, DEFAULT_TIMEOUT_MS);
2141 
2142         // Make sure we got the expected event.
2143         assertNotNull(ninethExpected);
2144 
2145         // Verify the selection position.
2146         assertEquals(11, Selection.getSelectionStart(editText.getText()));
2147         assertEquals(0, Selection.getSelectionEnd(editText.getText()));
2148 
2149         // Make sure there is no previous.
2150         assertFalse(text.performAction(
2151                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
2152 
2153         // Verify the selection position.
2154         assertEquals(11, Selection.getSelectionStart(editText.getText()));
2155         assertEquals(0, Selection.getSelectionEnd(editText.getText()));
2156 
2157         // Move to the next word and wait for an event.
2158         AccessibilityEvent tenthExpected = sUiAutomation
2159                 .executeAndWaitForEvent(new Runnable() {
2160             @Override
2161             public void run() {
2162                 text.performAction(
2163                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
2164             }
2165         }, new UiAutomation.AccessibilityEventFilter() {
2166             @Override
2167             public boolean accept(AccessibilityEvent event) {
2168                 return
2169                 (event.getEventType() ==
2170                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
2171                         && event.getAction() ==
2172                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
2173                         && event.getPackageName().equals(mActivity.getPackageName())
2174                         && event.getClassName().equals(EditText.class.getName())
2175                         && event.getText().size() > 0
2176                         && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
2177                         && event.getFromIndex() == 0
2178                         && event.getToIndex() == 3
2179                         && event.getMovementGranularity() ==
2180                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
2181             }
2182         }, DEFAULT_TIMEOUT_MS);
2183 
2184         // Make sure we got the expected event.
2185         assertNotNull(tenthExpected);
2186 
2187         // Verify the selection position.
2188         assertEquals(11, Selection.getSelectionStart(editText.getText()));
2189         assertEquals(3, Selection.getSelectionEnd(editText.getText()));
2190 
2191         // Move to the next word and wait for an event.
2192         AccessibilityEvent eleventhExpected = sUiAutomation
2193                 .executeAndWaitForEvent(new Runnable() {
2194             @Override
2195             public void run() {
2196                 text.performAction(
2197                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
2198             }
2199         }, new UiAutomation.AccessibilityEventFilter() {
2200             @Override
2201             public boolean accept(AccessibilityEvent event) {
2202                 return
2203                 (event.getEventType() ==
2204                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
2205                         && event.getAction() ==
2206                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
2207                         && event.getPackageName().equals(mActivity.getPackageName())
2208                         && event.getClassName().equals(EditText.class.getName())
2209                         && event.getText().size() > 0
2210                         && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
2211                         && event.getFromIndex() == 4
2212                         && event.getToIndex() == 7
2213                         && event.getMovementGranularity() ==
2214                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
2215             }
2216         }, DEFAULT_TIMEOUT_MS);
2217 
2218         // Make sure we got the expected event.
2219         assertNotNull(eleventhExpected);
2220 
2221         // Verify the selection position.
2222         assertEquals(11, Selection.getSelectionStart(editText.getText()));
2223         assertEquals(7, Selection.getSelectionEnd(editText.getText()));
2224 
2225         // Move to the next word and wait for an event.
2226         AccessibilityEvent twelvthExpected = sUiAutomation
2227                 .executeAndWaitForEvent(new Runnable() {
2228             @Override
2229             public void run() {
2230                 text.performAction(
2231                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
2232             }
2233         }, new UiAutomation.AccessibilityEventFilter() {
2234             @Override
2235             public boolean accept(AccessibilityEvent event) {
2236                 return
2237                 (event.getEventType() ==
2238                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
2239                         && event.getAction() ==
2240                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
2241                         && event.getPackageName().equals(mActivity.getPackageName())
2242                         && event.getClassName().equals(EditText.class.getName())
2243                         && event.getText().size() > 0
2244                         && event.getText().get(0).toString().equals(getString(R.string.foo_bar_baz))
2245                         && event.getFromIndex() == 8
2246                         && event.getToIndex() == 11
2247                         && event.getMovementGranularity() ==
2248                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
2249             }
2250         }, DEFAULT_TIMEOUT_MS);
2251 
2252         // Make sure we got the expected event.
2253         assertNotNull(twelvthExpected);
2254 
2255         // Verify the selection position.
2256         assertEquals(11, Selection.getSelectionStart(editText.getText()));
2257         assertEquals(11, Selection.getSelectionEnd(editText.getText()));
2258 
2259         // Make sure there is no next.
2260         assertFalse(text.performAction(
2261                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
2262 
2263         // Verify the selection position.
2264         assertEquals(11, Selection.getSelectionStart(editText.getText()));
2265         assertEquals(11, Selection.getSelectionEnd(editText.getText()));
2266     }
2267 
2268     @MediumTest
2269     @Test
testActionNextAndPreviousAtGranularityLineOverText()2270     public void testActionNextAndPreviousAtGranularityLineOverText() throws Exception {
2271         final TextView textView = (TextView) mActivity.findViewById(R.id.text);
2272 
2273         sInstrumentation.runOnMainSync(new Runnable() {
2274             @Override
2275             public void run() {
2276                 textView.setVisibility(View.VISIBLE);
2277                 textView.setText(getString(R.string.android_wiki_short));
2278             }
2279         });
2280 
2281         final AccessibilityNodeInfo text = sUiAutomation
2282                .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
2283                        R.string.android_wiki_short)).get(0);
2284 
2285         final int granularities = text.getMovementGranularities();
2286         assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
2287                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
2288                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
2289                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
2290                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
2291 
2292         final Bundle arguments = new Bundle();
2293         arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
2294                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
2295 
2296         // Move to the next line and wait for an event.
2297         AccessibilityEvent firstExpected = sUiAutomation
2298                 .executeAndWaitForEvent(new Runnable() {
2299             @Override
2300             public void run() {
2301                 text.performAction(
2302                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
2303             }
2304         }, new UiAutomation.AccessibilityEventFilter() {
2305             @Override
2306             public boolean accept(AccessibilityEvent event) {
2307                 return
2308                 (event.getEventType() ==
2309                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
2310                         && event.getAction() ==
2311                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
2312                         && event.getPackageName().equals(mActivity.getPackageName())
2313                         && event.getClassName().equals(TextView.class.getName())
2314                         && event.getText().size() > 0
2315                         && event.getText().get(0).toString().equals(getString(
2316                                 R.string.android_wiki_short))
2317                         && event.getFromIndex() == 0
2318                         && event.getToIndex() == 13
2319                         && event.getMovementGranularity() ==
2320                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
2321             }
2322         }, DEFAULT_TIMEOUT_MS);
2323 
2324         // Make sure we got the expected event.
2325         assertNotNull(firstExpected);
2326 
2327         // Verify the selection position.
2328         assertEquals(13, Selection.getSelectionStart(textView.getText()));
2329         assertEquals(13, Selection.getSelectionEnd(textView.getText()));
2330 
2331         // Move to the next line and wait for an event.
2332         AccessibilityEvent secondExpected = sUiAutomation
2333                 .executeAndWaitForEvent(new Runnable() {
2334             @Override
2335             public void run() {
2336                 text.performAction(
2337                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
2338             }
2339         }, new UiAutomation.AccessibilityEventFilter() {
2340             @Override
2341             public boolean accept(AccessibilityEvent event) {
2342                 return
2343                 (event.getEventType() ==
2344                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
2345                         && event.getAction() ==
2346                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
2347                         && event.getPackageName().equals(mActivity.getPackageName())
2348                         && event.getClassName().equals(TextView.class.getName())
2349                         && event.getText().size() > 0
2350                         && event.getText().get(0).toString().equals(getString(
2351                                 R.string.android_wiki_short))
2352                         && event.getFromIndex() == 13
2353                         && event.getToIndex() == 25
2354                         && event.getMovementGranularity() ==
2355                                  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
2356             }
2357         }, DEFAULT_TIMEOUT_MS);
2358 
2359         // Make sure we got the expected event.
2360         assertNotNull(secondExpected);
2361 
2362         // Verify the selection position.
2363         assertEquals(25, Selection.getSelectionStart(textView.getText()));
2364         assertEquals(25, Selection.getSelectionEnd(textView.getText()));
2365 
2366         // Move to the next line and wait for an event.
2367         AccessibilityEvent thirdExpected = sUiAutomation
2368                 .executeAndWaitForEvent(new Runnable() {
2369             @Override
2370             public void run() {
2371                 text.performAction(
2372                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
2373             }
2374         }, new UiAutomation.AccessibilityEventFilter() {
2375             @Override
2376             public boolean accept(AccessibilityEvent event) {
2377                 return
2378                 (event.getEventType() ==
2379                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
2380                         && event.getAction() ==
2381                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
2382                         && event.getPackageName().equals(mActivity.getPackageName())
2383                         && event.getClassName().equals(TextView.class.getName())
2384                         && event.getText().size() > 0
2385                         && event.getText().get(0).toString().equals(getString(
2386                                 R.string.android_wiki_short))
2387                         && event.getFromIndex() == 25
2388                         && event.getToIndex() == 34
2389                         && event.getMovementGranularity() ==
2390                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
2391             }
2392         }, DEFAULT_TIMEOUT_MS);
2393 
2394         // Make sure we got the expected event.
2395         assertNotNull(thirdExpected);
2396 
2397         // Verify the selection position.
2398         assertEquals(34, Selection.getSelectionStart(textView.getText()));
2399         assertEquals(34, Selection.getSelectionEnd(textView.getText()));
2400 
2401         // Make sure there is no next.
2402         assertFalse(text.performAction(
2403                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
2404 
2405         // Verify the selection position.
2406         assertEquals(34, Selection.getSelectionStart(textView.getText()));
2407         assertEquals(34, Selection.getSelectionEnd(textView.getText()));
2408 
2409         // Move to the previous line and wait for an event.
2410         AccessibilityEvent fourthExpected = sUiAutomation
2411                 .executeAndWaitForEvent(new Runnable() {
2412             @Override
2413             public void run() {
2414                 text.performAction(
2415                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
2416             }
2417         }, new UiAutomation.AccessibilityEventFilter() {
2418             @Override
2419             public boolean accept(AccessibilityEvent event) {
2420                 return
2421                 (event.getEventType() ==
2422                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
2423                         && event.getAction() ==
2424                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
2425                         && event.getPackageName().equals(mActivity.getPackageName())
2426                         && event.getClassName().equals(TextView.class.getName())
2427                         && event.getText().size() > 0
2428                         && event.getText().get(0).toString().equals(getString(
2429                                 R.string.android_wiki_short))
2430                         && event.getFromIndex() == 25
2431                         && event.getToIndex() == 34
2432                         && event.getMovementGranularity() ==
2433                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
2434             }
2435         }, DEFAULT_TIMEOUT_MS);
2436 
2437         // Make sure we got the expected event.
2438         assertNotNull(fourthExpected);
2439 
2440         // Verify the selection position.
2441         assertEquals(25, Selection.getSelectionStart(textView.getText()));
2442         assertEquals(25, Selection.getSelectionEnd(textView.getText()));
2443 
2444         // Move to the previous line and wait for an event.
2445         AccessibilityEvent fifthExpected = sUiAutomation
2446                 .executeAndWaitForEvent(new Runnable() {
2447             @Override
2448             public void run() {
2449                 text.performAction(
2450                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
2451             }
2452         }, new UiAutomation.AccessibilityEventFilter() {
2453             @Override
2454             public boolean accept(AccessibilityEvent event) {
2455                 return
2456                 (event.getEventType() ==
2457                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
2458                         && event.getAction() ==
2459                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
2460                         && event.getPackageName().equals(mActivity.getPackageName())
2461                         && event.getClassName().equals(TextView.class.getName())
2462                         && event.getText().size() > 0
2463                         && event.getText().get(0).toString().equals(getString(
2464                                 R.string.android_wiki_short))
2465                         && event.getFromIndex() == 13
2466                         && event.getToIndex() == 25
2467                         && event.getMovementGranularity() ==
2468                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
2469             }
2470         }, DEFAULT_TIMEOUT_MS);
2471 
2472         // Make sure we got the expected event.
2473         assertNotNull(fifthExpected);
2474 
2475         // Verify the selection position.
2476         assertEquals(13, Selection.getSelectionStart(textView.getText()));
2477         assertEquals(13, Selection.getSelectionEnd(textView.getText()));
2478 
2479         // Move to the previous line and wait for an event.
2480         AccessibilityEvent sixthExpected = sUiAutomation
2481                 .executeAndWaitForEvent(new Runnable() {
2482             @Override
2483             public void run() {
2484                 text.performAction(
2485                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
2486             }
2487         }, new UiAutomation.AccessibilityEventFilter() {
2488             @Override
2489             public boolean accept(AccessibilityEvent event) {
2490                 return
2491                 (event.getEventType() ==
2492                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
2493                         && event.getAction() ==
2494                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
2495                         && event.getPackageName().equals(mActivity.getPackageName())
2496                         && event.getClassName().equals(TextView.class.getName())
2497                         && event.getText().size() > 0
2498                         && event.getText().get(0).toString().equals(getString(
2499                                 R.string.android_wiki_short))
2500                         && event.getFromIndex() == 0
2501                         && event.getToIndex() == 13
2502                         && event.getMovementGranularity() ==
2503                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
2504             }
2505         }, DEFAULT_TIMEOUT_MS);
2506 
2507         // Make sure we got the expected event.
2508         assertNotNull(sixthExpected);
2509 
2510         // Verify the selection position.
2511         assertEquals(0, Selection.getSelectionStart(textView.getText()));
2512         assertEquals(0, Selection.getSelectionEnd(textView.getText()));
2513 
2514         // Make sure there is no previous.
2515         assertFalse(text.performAction(
2516                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
2517 
2518         // Verify the selection position.
2519         assertEquals(0, Selection.getSelectionStart(textView.getText()));
2520         assertEquals(0, Selection.getSelectionEnd(textView.getText()));
2521     }
2522 
2523     @MediumTest
2524     @Test
testActionNextAndPreviousAtGranularityLineOverTextExtend()2525     public void testActionNextAndPreviousAtGranularityLineOverTextExtend() throws Exception {
2526         final EditText editText = (EditText) mActivity.findViewById(R.id.edit);
2527 
2528         sInstrumentation.runOnMainSync(new Runnable() {
2529             @Override
2530             public void run() {
2531                 editText.setVisibility(View.VISIBLE);
2532                 editText.setText(getString(R.string.android_wiki_short));
2533                 Selection.removeSelection(editText.getText());
2534             }
2535         });
2536 
2537         final AccessibilityNodeInfo text = sUiAutomation
2538                .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
2539                        R.string.android_wiki_short)).get(0);
2540 
2541         final int granularities = text.getMovementGranularities();
2542         assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
2543                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
2544                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
2545                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
2546                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
2547 
2548         final Bundle arguments = new Bundle();
2549         arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
2550                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
2551         arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, true);
2552 
2553         // Move to the next line and wait for an event.
2554         AccessibilityEvent firstExpected = sUiAutomation
2555                 .executeAndWaitForEvent(new Runnable() {
2556             @Override
2557             public void run() {
2558                 text.performAction(
2559                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
2560             }
2561         }, new UiAutomation.AccessibilityEventFilter() {
2562             @Override
2563             public boolean accept(AccessibilityEvent event) {
2564                 return
2565                 (event.getEventType() ==
2566                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
2567                         && event.getAction() ==
2568                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
2569                         && event.getPackageName().equals(mActivity.getPackageName())
2570                         && event.getClassName().equals(EditText.class.getName())
2571                         && event.getText().size() > 0
2572                         && event.getText().get(0).toString().equals(getString(
2573                                 R.string.android_wiki_short))
2574                         && event.getFromIndex() == 0
2575                         && event.getToIndex() == 13
2576                         && event.getMovementGranularity() ==
2577                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
2578             }
2579         }, DEFAULT_TIMEOUT_MS);
2580 
2581         // Make sure we got the expected event.
2582         assertNotNull(firstExpected);
2583 
2584         // Verify the selection position.
2585         assertEquals(0, Selection.getSelectionStart(editText.getText()));
2586         assertEquals(13, Selection.getSelectionEnd(editText.getText()));
2587 
2588         // Move to the next line and wait for an event.
2589         AccessibilityEvent secondExpected = sUiAutomation
2590                 .executeAndWaitForEvent(new Runnable() {
2591             @Override
2592             public void run() {
2593                 text.performAction(
2594                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
2595             }
2596         }, new UiAutomation.AccessibilityEventFilter() {
2597             @Override
2598             public boolean accept(AccessibilityEvent event) {
2599                 return
2600                 (event.getEventType() ==
2601                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
2602                         && event.getAction() ==
2603                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
2604                         && event.getPackageName().equals(mActivity.getPackageName())
2605                         && event.getClassName().equals(EditText.class.getName())
2606                         && event.getText().size() > 0
2607                         && event.getText().get(0).toString().equals(getString(
2608                                 R.string.android_wiki_short))
2609                         && event.getFromIndex() == 13
2610                         && event.getToIndex() == 25
2611                         && event.getMovementGranularity() ==
2612                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
2613             }
2614         }, DEFAULT_TIMEOUT_MS);
2615 
2616         // Make sure we got the expected event.
2617         assertNotNull(secondExpected);
2618 
2619         // Verify the selection position.
2620         assertEquals(0, Selection.getSelectionStart(editText.getText()));
2621         assertEquals(25, Selection.getSelectionEnd(editText.getText()));
2622 
2623         // Move to the next line and wait for an event.
2624         AccessibilityEvent thirdExpected = sUiAutomation
2625                 .executeAndWaitForEvent(new Runnable() {
2626             @Override
2627             public void run() {
2628                 text.performAction(
2629                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
2630             }
2631         }, new UiAutomation.AccessibilityEventFilter() {
2632             @Override
2633             public boolean accept(AccessibilityEvent event) {
2634                 return
2635                 (event.getEventType() ==
2636                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
2637                         && event.getAction() ==
2638                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
2639                         && event.getPackageName().equals(mActivity.getPackageName())
2640                         && event.getClassName().equals(EditText.class.getName())
2641                         && event.getText().size() > 0
2642                         && event.getText().get(0).toString().equals(getString(
2643                                 R.string.android_wiki_short))
2644                         && event.getFromIndex() == 25
2645                         && event.getToIndex() == 34
2646                         && event.getMovementGranularity() ==
2647                                  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
2648             }
2649         }, DEFAULT_TIMEOUT_MS);
2650 
2651         // Make sure we got the expected event.
2652         assertNotNull(thirdExpected);
2653 
2654         // Verify the selection position.
2655         assertEquals(0, Selection.getSelectionStart(editText.getText()));
2656         assertEquals(34, Selection.getSelectionEnd(editText.getText()));
2657 
2658         // Move to the previous line and wait for an event.
2659         AccessibilityEvent fourthExpected = sUiAutomation
2660                 .executeAndWaitForEvent(new Runnable() {
2661             @Override
2662             public void run() {
2663                 text.performAction(
2664                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
2665             }
2666         }, new UiAutomation.AccessibilityEventFilter() {
2667             @Override
2668             public boolean accept(AccessibilityEvent event) {
2669                 return
2670                 (event.getEventType() ==
2671                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
2672                         && event.getAction() ==
2673                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
2674                         && event.getPackageName().equals(mActivity.getPackageName())
2675                         && event.getClassName().equals(EditText.class.getName())
2676                         && event.getText().size() > 0
2677                         && event.getText().get(0).toString().equals(getString(
2678                                 R.string.android_wiki_short))
2679                         && event.getFromIndex() == 25
2680                         && event.getToIndex() == 34
2681                         && event.getMovementGranularity() ==
2682                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
2683             }
2684         }, DEFAULT_TIMEOUT_MS);
2685 
2686         // Make sure we got the expected event.
2687         assertNotNull(fourthExpected);
2688 
2689         // Verify the selection position.
2690         assertEquals(0, Selection.getSelectionStart(editText.getText()));
2691         assertEquals(25, Selection.getSelectionEnd(editText.getText()));
2692 
2693         // Move to the previous line and wait for an event.
2694         AccessibilityEvent fifthExpected = sUiAutomation
2695                 .executeAndWaitForEvent(new Runnable() {
2696             @Override
2697             public void run() {
2698                 text.performAction(
2699                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
2700             }
2701         }, new UiAutomation.AccessibilityEventFilter() {
2702             @Override
2703             public boolean accept(AccessibilityEvent event) {
2704                 return
2705                 (event.getEventType() ==
2706                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
2707                         && event.getAction() ==
2708                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
2709                         && event.getPackageName().equals(mActivity.getPackageName())
2710                         && event.getClassName().equals(EditText.class.getName())
2711                         && event.getText().size() > 0
2712                         && event.getText().get(0).toString().equals(getString(
2713                                 R.string.android_wiki_short))
2714                         && event.getFromIndex() == 13
2715                         && event.getToIndex() == 25
2716                         && event.getMovementGranularity() ==
2717                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
2718             }
2719         }, DEFAULT_TIMEOUT_MS);
2720 
2721         // Make sure we got the expected event.
2722         assertNotNull(fifthExpected);
2723 
2724         // Verify the selection position.
2725         assertEquals(0, Selection.getSelectionStart(editText.getText()));
2726         assertEquals(13, Selection.getSelectionEnd(editText.getText()));
2727 
2728         // Move to the previous line and wait for an event.
2729         AccessibilityEvent sixthExpected = sUiAutomation
2730                 .executeAndWaitForEvent(new Runnable() {
2731             @Override
2732             public void run() {
2733                 text.performAction(
2734                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
2735             }
2736         }, new UiAutomation.AccessibilityEventFilter() {
2737             @Override
2738             public boolean accept(AccessibilityEvent event) {
2739                 return
2740                 (event.getEventType() ==
2741                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
2742                         && event.getAction() ==
2743                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
2744                         && event.getPackageName().equals(mActivity.getPackageName())
2745                         && event.getClassName().equals(EditText.class.getName())
2746                         && event.getText().size() > 0
2747                         && event.getText().get(0).toString().equals(getString(
2748                                 R.string.android_wiki_short))
2749                         && event.getFromIndex() == 0
2750                         && event.getToIndex() == 13
2751                         && event.getMovementGranularity() ==
2752                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
2753             }
2754         }, DEFAULT_TIMEOUT_MS);
2755 
2756         // Make sure we got the expected event.
2757         assertNotNull(sixthExpected);
2758 
2759         // Verify the selection position.
2760         assertEquals(0, Selection.getSelectionStart(editText.getText()));
2761         assertEquals(0, Selection.getSelectionEnd(editText.getText()));
2762 
2763         // Make sure there is no previous.
2764         assertFalse(text.performAction(
2765                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
2766 
2767         // Verify the selection position.
2768         assertEquals(0, Selection.getSelectionStart(editText.getText()));
2769         assertEquals(0, Selection.getSelectionEnd(editText.getText()));
2770 
2771         // Focus the view so we can change selection.
2772         sInstrumentation.runOnMainSync(new Runnable() {
2773             @Override
2774             public void run() {
2775                 editText.setFocusable(true);
2776                 editText.requestFocus();
2777             }
2778         });
2779 
2780         // Put selection at the end of the text.
2781         Bundle setSelectionArgs = new Bundle();
2782         setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 34);
2783         setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 34);
2784         assertTrue(text.performAction(
2785                 AccessibilityNodeInfo.ACTION_SET_SELECTION, setSelectionArgs));
2786 
2787         // Verify the selection position.
2788         assertEquals(34, Selection.getSelectionStart(editText.getText()));
2789         assertEquals(34, Selection.getSelectionEnd(editText.getText()));
2790 
2791         // Move to the previous line and wait for an event.
2792         AccessibilityEvent seventhExpected = sUiAutomation
2793                 .executeAndWaitForEvent(new Runnable() {
2794             @Override
2795             public void run() {
2796                 text.performAction(
2797                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
2798             }
2799         }, new UiAutomation.AccessibilityEventFilter() {
2800             @Override
2801             public boolean accept(AccessibilityEvent event) {
2802                 return
2803                 (event.getEventType() ==
2804                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
2805                         && event.getAction() ==
2806                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
2807                         && event.getPackageName().equals(mActivity.getPackageName())
2808                         && event.getClassName().equals(EditText.class.getName())
2809                         && event.getText().size() > 0
2810                         && event.getText().get(0).toString().equals(getString(
2811                                 R.string.android_wiki_short))
2812                         && event.getFromIndex() == 25
2813                         && event.getToIndex() == 34
2814                         && event.getMovementGranularity() ==
2815                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
2816             }
2817         }, DEFAULT_TIMEOUT_MS);
2818 
2819         // Make sure we got the expected event.
2820         assertNotNull(seventhExpected);
2821 
2822         // Verify the selection position.
2823         assertEquals(34, Selection.getSelectionStart(editText.getText()));
2824         assertEquals(25, Selection.getSelectionEnd(editText.getText()));
2825 
2826         // Move to the previous line and wait for an event.
2827         AccessibilityEvent eightExpected = sUiAutomation
2828                 .executeAndWaitForEvent(new Runnable() {
2829             @Override
2830             public void run() {
2831                 text.performAction(
2832                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
2833             }
2834         }, new UiAutomation.AccessibilityEventFilter() {
2835             @Override
2836             public boolean accept(AccessibilityEvent event) {
2837                 return
2838                 (event.getEventType() ==
2839                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
2840                         && event.getAction() ==
2841                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
2842                         && event.getPackageName().equals(mActivity.getPackageName())
2843                         && event.getClassName().equals(EditText.class.getName())
2844                         && event.getText().size() > 0
2845                         && event.getText().get(0).toString().equals(getString(
2846                                 R.string.android_wiki_short))
2847                         && event.getFromIndex() == 13
2848                         && event.getToIndex() == 25
2849                         && event.getMovementGranularity() ==
2850                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
2851             }
2852         }, DEFAULT_TIMEOUT_MS);
2853 
2854         // Make sure we got the expected event.
2855         assertNotNull(eightExpected);
2856 
2857         // Verify the selection position.
2858         assertEquals(34, Selection.getSelectionStart(editText.getText()));
2859         assertEquals(13, Selection.getSelectionEnd(editText.getText()));
2860 
2861         // Move to the previous line and wait for an event.
2862         AccessibilityEvent ninethExpected = sUiAutomation
2863                 .executeAndWaitForEvent(new Runnable() {
2864             @Override
2865             public void run() {
2866                 text.performAction(
2867                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
2868             }
2869         }, new UiAutomation.AccessibilityEventFilter() {
2870             @Override
2871             public boolean accept(AccessibilityEvent event) {
2872                 return
2873                 (event.getEventType() ==
2874                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
2875                         && event.getAction() ==
2876                                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
2877                         && event.getPackageName().equals(mActivity.getPackageName())
2878                         && event.getClassName().equals(EditText.class.getName())
2879                         && event.getText().size() > 0
2880                         && event.getText().get(0).toString().equals(getString(
2881                                 R.string.android_wiki_short))
2882                         && event.getFromIndex() == 0
2883                         && event.getToIndex() == 13
2884                         && event.getMovementGranularity() ==
2885                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
2886             }
2887         }, DEFAULT_TIMEOUT_MS);
2888 
2889         // Make sure we got the expected event.
2890         assertNotNull(ninethExpected);
2891 
2892         // Verify the selection position.
2893         assertEquals(34, Selection.getSelectionStart(editText.getText()));
2894         assertEquals(0, Selection.getSelectionEnd(editText.getText()));
2895 
2896         // Make sure there is no previous.
2897         assertFalse(text.performAction(
2898                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
2899 
2900         // Verify the selection position.
2901         assertEquals(34, Selection.getSelectionStart(editText.getText()));
2902         assertEquals(0, Selection.getSelectionEnd(editText.getText()));
2903 
2904         // Move to the next line and wait for an event.
2905         AccessibilityEvent tenthExpected = sUiAutomation
2906                 .executeAndWaitForEvent(new Runnable() {
2907             @Override
2908             public void run() {
2909                 text.performAction(
2910                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
2911             }
2912         }, new UiAutomation.AccessibilityEventFilter() {
2913             @Override
2914             public boolean accept(AccessibilityEvent event) {
2915                 return
2916                 (event.getEventType() ==
2917                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
2918                         && event.getAction() ==
2919                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
2920                         && event.getPackageName().equals(mActivity.getPackageName())
2921                         && event.getClassName().equals(EditText.class.getName())
2922                         && event.getText().size() > 0
2923                         && event.getText().get(0).toString().equals(getString(
2924                                 R.string.android_wiki_short))
2925                         && event.getFromIndex() == 0
2926                         && event.getToIndex() == 13
2927                         && event.getMovementGranularity() ==
2928                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
2929             }
2930         }, DEFAULT_TIMEOUT_MS);
2931 
2932         // Make sure we got the expected event.
2933         assertNotNull(tenthExpected);
2934 
2935         // Verify the selection position.
2936         assertEquals(34, Selection.getSelectionStart(editText.getText()));
2937         assertEquals(13, Selection.getSelectionEnd(editText.getText()));
2938 
2939         // Move to the next line and wait for an event.
2940         AccessibilityEvent eleventhExpected = sUiAutomation
2941                 .executeAndWaitForEvent(new Runnable() {
2942             @Override
2943             public void run() {
2944                 text.performAction(
2945                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
2946             }
2947         }, new UiAutomation.AccessibilityEventFilter() {
2948             @Override
2949             public boolean accept(AccessibilityEvent event) {
2950                 return
2951                 (event.getEventType() ==
2952                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
2953                         && event.getAction() ==
2954                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
2955                         && event.getPackageName().equals(mActivity.getPackageName())
2956                         && event.getClassName().equals(EditText.class.getName())
2957                         && event.getText().size() > 0
2958                         && event.getText().get(0).toString().equals(getString(
2959                                 R.string.android_wiki_short))
2960                         && event.getFromIndex() == 13
2961                         && event.getToIndex() == 25
2962                         && event.getMovementGranularity() ==
2963                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
2964             }
2965         }, DEFAULT_TIMEOUT_MS);
2966 
2967         // Make sure we got the expected event.
2968         assertNotNull(eleventhExpected);
2969 
2970         // Verify the selection position.
2971         assertEquals(34, Selection.getSelectionStart(editText.getText()));
2972         assertEquals(25, Selection.getSelectionEnd(editText.getText()));
2973 
2974         // Move to the next line and wait for an event.
2975         AccessibilityEvent twelvethExpected = sUiAutomation
2976                 .executeAndWaitForEvent(new Runnable() {
2977             @Override
2978             public void run() {
2979                 text.performAction(
2980                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
2981             }
2982         }, new UiAutomation.AccessibilityEventFilter() {
2983             @Override
2984             public boolean accept(AccessibilityEvent event) {
2985                 return
2986                 (event.getEventType() ==
2987                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
2988                         && event.getAction() ==
2989                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
2990                         && event.getPackageName().equals(mActivity.getPackageName())
2991                         && event.getClassName().equals(EditText.class.getName())
2992                         && event.getText().size() > 0
2993                         && event.getText().get(0).toString().equals(getString(
2994                                 R.string.android_wiki_short))
2995                         && event.getFromIndex() == 25
2996                         && event.getToIndex() == 34
2997                         && event.getMovementGranularity() ==
2998                                  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
2999             }
3000         }, DEFAULT_TIMEOUT_MS);
3001 
3002         // Make sure we got the expected event.
3003         assertNotNull(twelvethExpected);
3004 
3005         // Verify the selection position.
3006         assertEquals(34, Selection.getSelectionStart(editText.getText()));
3007         assertEquals(34, Selection.getSelectionEnd(editText.getText()));
3008     }
3009 
3010     @MediumTest
3011     @Test
testActionNextAndPreviousAtGranularityParagraphOverText()3012     public void testActionNextAndPreviousAtGranularityParagraphOverText() throws Exception {
3013         final TextView textView = (TextView) mActivity.findViewById(R.id.edit);
3014 
3015         sInstrumentation.runOnMainSync(new Runnable() {
3016             @Override
3017             public void run() {
3018                 textView.setVisibility(View.VISIBLE);
3019                 textView.setText(getString(R.string.android_wiki_paragraphs));
3020             }
3021         });
3022 
3023         final AccessibilityNodeInfo text = sUiAutomation
3024                .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
3025                        R.string.android_wiki_paragraphs)).get(0);
3026 
3027         final int granularities = text.getMovementGranularities();
3028         assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
3029                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
3030                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
3031                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
3032                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
3033 
3034         final Bundle arguments = new Bundle();
3035         arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
3036                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
3037 
3038         // Move to the next paragraph and wait for an event.
3039         AccessibilityEvent firstExpected = sUiAutomation
3040                 .executeAndWaitForEvent(new Runnable() {
3041             @Override
3042             public void run() {
3043                 text.performAction(
3044                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
3045             }
3046         }, new UiAutomation.AccessibilityEventFilter() {
3047             @Override
3048             public boolean accept(AccessibilityEvent event) {
3049                 return
3050                 (event.getEventType() ==
3051                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
3052                         && event.getAction() ==
3053                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
3054                         && event.getPackageName().equals(mActivity.getPackageName())
3055                         && event.getClassName().equals(EditText.class.getName())
3056                         && event.getText().size() > 0
3057                         && event.getText().get(0).toString().equals(getString(
3058                                 R.string.android_wiki_paragraphs))
3059                         && event.getFromIndex() == 2
3060                         && event.getToIndex() == 14
3061                         && event.getMovementGranularity() ==
3062                                  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
3063             }
3064         }, DEFAULT_TIMEOUT_MS);
3065 
3066         // Make sure we got the expected event.
3067         assertNotNull(firstExpected);
3068 
3069         // Verify the selection position.
3070         assertEquals(14, Selection.getSelectionStart(textView.getText()));
3071         assertEquals(14, Selection.getSelectionEnd(textView.getText()));
3072 
3073         // Move to the next paragraph and wait for an event.
3074         AccessibilityEvent secondExpected = sUiAutomation
3075                 .executeAndWaitForEvent(new Runnable() {
3076             @Override
3077             public void run() {
3078                 text.performAction(
3079                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
3080             }
3081         }, new UiAutomation.AccessibilityEventFilter() {
3082             @Override
3083             public boolean accept(AccessibilityEvent event) {
3084                 return
3085                 (event.getEventType() ==
3086                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
3087                         && event.getAction() ==
3088                                  AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
3089                         && event.getPackageName().equals(mActivity.getPackageName())
3090                         && event.getClassName().equals(EditText.class.getName())
3091                         && event.getText().size() > 0
3092                         && event.getText().get(0).toString().equals(getString(
3093                                 R.string.android_wiki_paragraphs))
3094                         && event.getFromIndex() == 16
3095                         && event.getToIndex() == 32
3096                         && event.getMovementGranularity() ==
3097                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
3098             }
3099         }, DEFAULT_TIMEOUT_MS);
3100 
3101         // Make sure we got the expected event.
3102         assertNotNull(secondExpected);
3103 
3104         // Verify the selection position.
3105         assertEquals(32, Selection.getSelectionStart(textView.getText()));
3106         assertEquals(32, Selection.getSelectionEnd(textView.getText()));
3107 
3108         // Move to the next paragraph and wait for an event.
3109         AccessibilityEvent thirdExpected = sUiAutomation
3110                 .executeAndWaitForEvent(new Runnable() {
3111             @Override
3112             public void run() {
3113                 text.performAction(
3114                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
3115             }
3116         }, new UiAutomation.AccessibilityEventFilter() {
3117             @Override
3118             public boolean accept(AccessibilityEvent event) {
3119                 return
3120                 (event.getEventType() ==
3121                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
3122                         && event.getAction() ==
3123                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
3124                         && event.getPackageName().equals(mActivity.getPackageName())
3125                         && event.getClassName().equals(EditText.class.getName())
3126                         && event.getText().size() > 0
3127                         && event.getText().get(0).toString().equals(getString(
3128                                 R.string.android_wiki_paragraphs))
3129                         && event.getFromIndex() == 33
3130                         && event.getToIndex() == 47
3131                         && event.getMovementGranularity() ==
3132                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
3133             }
3134         }, DEFAULT_TIMEOUT_MS);
3135 
3136         // Make sure we got the expected event.
3137         assertNotNull(thirdExpected);
3138 
3139         // Verify the selection position.
3140         assertEquals(47, Selection.getSelectionStart(textView.getText()));
3141         assertEquals(47, Selection.getSelectionEnd(textView.getText()));
3142 
3143         // Make sure there is no next.
3144         assertFalse(text.performAction(
3145                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
3146 
3147         // Verify the selection position.
3148         assertEquals(47, Selection.getSelectionStart(textView.getText()));
3149         assertEquals(47, Selection.getSelectionEnd(textView.getText()));
3150 
3151         // Move to the previous paragraph and wait for an event.
3152         AccessibilityEvent fourthExpected = sUiAutomation
3153                 .executeAndWaitForEvent(new Runnable() {
3154             @Override
3155             public void run() {
3156                 text.performAction(
3157                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
3158             }
3159         }, new UiAutomation.AccessibilityEventFilter() {
3160             @Override
3161             public boolean accept(AccessibilityEvent event) {
3162                 return
3163                 (event.getEventType() ==
3164                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
3165                         && event.getAction() ==
3166                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
3167                         && event.getPackageName().equals(mActivity.getPackageName())
3168                         && event.getClassName().equals(EditText.class.getName())
3169                         && event.getText().size() > 0
3170                         && event.getText().get(0).toString().equals(getString(
3171                                 R.string.android_wiki_paragraphs))
3172                         && event.getFromIndex() == 33
3173                         && event.getToIndex() == 47
3174                         && event.getMovementGranularity() ==
3175                                  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
3176             }
3177         }, DEFAULT_TIMEOUT_MS);
3178 
3179         // Make sure we got the expected event.
3180         assertNotNull(fourthExpected);
3181 
3182         // Verify the selection position.
3183         assertEquals(33, Selection.getSelectionStart(textView.getText()));
3184         assertEquals(33, Selection.getSelectionEnd(textView.getText()));
3185 
3186         // Move to the previous paragraph and wait for an event.
3187         AccessibilityEvent fifthExpected = sUiAutomation
3188                 .executeAndWaitForEvent(new Runnable() {
3189             @Override
3190             public void run() {
3191                 text.performAction(
3192                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
3193             }
3194         }, new UiAutomation.AccessibilityEventFilter() {
3195             @Override
3196             public boolean accept(AccessibilityEvent event) {
3197                 return
3198                 (event.getEventType() ==
3199                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
3200                         && event.getAction() ==
3201                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
3202                         && event.getPackageName().equals(mActivity.getPackageName())
3203                         && event.getClassName().equals(EditText.class.getName())
3204                         && event.getText().size() > 0
3205                         && event.getText().get(0).toString().equals(getString(
3206                                 R.string.android_wiki_paragraphs))
3207                         && event.getFromIndex() == 16
3208                         && event.getToIndex() == 32
3209                         && event.getMovementGranularity() ==
3210                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
3211             }
3212         }, DEFAULT_TIMEOUT_MS);
3213 
3214         // Make sure we got the expected event.
3215         assertNotNull(fifthExpected);
3216 
3217         // Verify the selection position.
3218         assertEquals(16, Selection.getSelectionStart(textView.getText()));
3219         assertEquals(16, Selection.getSelectionEnd(textView.getText()));
3220 
3221         // Move to the previous paragraph and wait for an event.
3222         AccessibilityEvent sixthExpected = sUiAutomation
3223                 .executeAndWaitForEvent(new Runnable() {
3224             @Override
3225             public void run() {
3226                 text.performAction(
3227                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
3228             }
3229         }, new UiAutomation.AccessibilityEventFilter() {
3230             @Override
3231             public boolean accept(AccessibilityEvent event) {
3232                 return
3233                 (event.getEventType() ==
3234                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
3235                         && event.getAction() ==
3236                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
3237                         && event.getPackageName().equals(mActivity.getPackageName())
3238                         && event.getClassName().equals(EditText.class.getName())
3239                         && event.getText().size() > 0
3240                         && event.getText().get(0).toString().equals(getString(
3241                                 R.string.android_wiki_paragraphs))
3242                         && event.getFromIndex() == 2
3243                         && event.getToIndex() == 14
3244                         && event.getMovementGranularity() ==
3245                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
3246             }
3247         }, DEFAULT_TIMEOUT_MS);
3248 
3249         // Make sure we got the expected event.
3250         assertNotNull(sixthExpected);
3251 
3252         // Verify the selection position.
3253         assertEquals(2, Selection.getSelectionStart(textView.getText()));
3254         assertEquals(2, Selection.getSelectionEnd(textView.getText()));
3255 
3256         // Make sure there is no previous.
3257         assertFalse(text.performAction(
3258                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
3259 
3260         // Verify the selection position.
3261         assertEquals(2, Selection.getSelectionStart(textView.getText()));
3262         assertEquals(2, Selection.getSelectionEnd(textView.getText()));
3263     }
3264 
3265     @MediumTest
3266     @Test
testActionNextAndPreviousAtGranularityParagraphOverTextExtend()3267     public void testActionNextAndPreviousAtGranularityParagraphOverTextExtend() throws Exception {
3268         final EditText editText = (EditText) mActivity.findViewById(R.id.edit);
3269 
3270         sInstrumentation.runOnMainSync(new Runnable() {
3271             @Override
3272             public void run() {
3273                 editText.setVisibility(View.VISIBLE);
3274                 editText.setText(getString(R.string.android_wiki_paragraphs));
3275                 Selection.removeSelection(editText.getText());
3276             }
3277         });
3278 
3279         final AccessibilityNodeInfo text = sUiAutomation
3280                .getRootInActiveWindow().findAccessibilityNodeInfosByText(getString(
3281                        R.string.android_wiki_paragraphs)).get(0);
3282 
3283         final int granularities = text.getMovementGranularities();
3284         assertEquals(granularities, AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
3285                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
3286                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
3287                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
3288                 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
3289 
3290         final Bundle arguments = new Bundle();
3291         arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
3292                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
3293         arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, true);
3294 
3295         // Move to the next paragraph and wait for an event.
3296         AccessibilityEvent firstExpected = sUiAutomation
3297                 .executeAndWaitForEvent(new Runnable() {
3298             @Override
3299             public void run() {
3300                 text.performAction(
3301                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
3302             }
3303         }, new UiAutomation.AccessibilityEventFilter() {
3304             @Override
3305             public boolean accept(AccessibilityEvent event) {
3306                 return
3307                 (event.getEventType() ==
3308                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
3309                         && event.getAction() ==
3310                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
3311                         && event.getPackageName().equals(mActivity.getPackageName())
3312                         && event.getClassName().equals(EditText.class.getName())
3313                         && event.getText().size() > 0
3314                         && event.getText().get(0).toString().equals(getString(
3315                                 R.string.android_wiki_paragraphs))
3316                         && event.getFromIndex() == 2
3317                         && event.getToIndex() == 14
3318                         && event.getMovementGranularity() ==
3319                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
3320             }
3321         }, DEFAULT_TIMEOUT_MS);
3322 
3323         // Make sure we got the expected event.
3324         assertNotNull(firstExpected);
3325 
3326         // Verify the selection position.
3327         assertEquals(2, Selection.getSelectionStart(editText.getText()));
3328         assertEquals(14, Selection.getSelectionEnd(editText.getText()));
3329 
3330         // Move to the next paragraph and wait for an event.
3331         AccessibilityEvent secondExpected = sUiAutomation
3332                 .executeAndWaitForEvent(new Runnable() {
3333             @Override
3334             public void run() {
3335                 text.performAction(
3336                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
3337             }
3338         }, new UiAutomation.AccessibilityEventFilter() {
3339             @Override
3340             public boolean accept(AccessibilityEvent event) {
3341                 return
3342                 (event.getEventType() ==
3343                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
3344                         && event.getAction() ==
3345                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
3346                         && event.getPackageName().equals(mActivity.getPackageName())
3347                         && event.getClassName().equals(EditText.class.getName())
3348                         && event.getText().size() > 0
3349                         && event.getText().get(0).toString().equals(getString(
3350                                 R.string.android_wiki_paragraphs))
3351                         && event.getFromIndex() == 16
3352                         && event.getToIndex() == 32
3353                         && event.getMovementGranularity() ==
3354                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
3355             }
3356         }, DEFAULT_TIMEOUT_MS);
3357 
3358         // Make sure we got the expected event.
3359         assertNotNull(secondExpected);
3360 
3361         // Verify the selection position.
3362         assertEquals(2, Selection.getSelectionStart(editText.getText()));
3363         assertEquals(32, Selection.getSelectionEnd(editText.getText()));
3364 
3365         // Move to the next paragraph and wait for an event.
3366         AccessibilityEvent thirdExpected = sUiAutomation
3367                 .executeAndWaitForEvent(new Runnable() {
3368             @Override
3369             public void run() {
3370                 text.performAction(
3371                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
3372             }
3373         }, new UiAutomation.AccessibilityEventFilter() {
3374             @Override
3375             public boolean accept(AccessibilityEvent event) {
3376                 return
3377                 (event.getEventType() ==
3378                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
3379                         && event.getAction() ==
3380                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
3381                         && event.getPackageName().equals(mActivity.getPackageName())
3382                         && event.getClassName().equals(EditText.class.getName())
3383                         && event.getText().size() > 0
3384                         && event.getText().get(0).toString().equals(getString(
3385                                 R.string.android_wiki_paragraphs))
3386                         && event.getFromIndex() == 33
3387                         && event.getToIndex() == 47
3388                         && event.getMovementGranularity() ==
3389                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
3390             }
3391         }, DEFAULT_TIMEOUT_MS);
3392 
3393         // Make sure we got the expected event.
3394         assertNotNull(thirdExpected);
3395 
3396         // Verify the selection position.
3397         assertEquals(2, Selection.getSelectionStart(editText.getText()));
3398         assertEquals(47, Selection.getSelectionEnd(editText.getText()));
3399 
3400         // Make sure there is no next.
3401         assertFalse(text.performAction(
3402                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
3403 
3404         // Verify the selection position.
3405         assertEquals(2, Selection.getSelectionStart(editText.getText()));
3406         assertEquals(47, Selection.getSelectionEnd(editText.getText()));
3407 
3408         // Move to the previous paragraph and wait for an event.
3409         AccessibilityEvent fourthExpected = sUiAutomation
3410                 .executeAndWaitForEvent(new Runnable() {
3411             @Override
3412             public void run() {
3413                 text.performAction(
3414                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
3415             }
3416         }, new UiAutomation.AccessibilityEventFilter() {
3417             @Override
3418             public boolean accept(AccessibilityEvent event) {
3419                 return
3420                 (event.getEventType() ==
3421                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
3422                         && event.getAction() ==
3423                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
3424                         && event.getPackageName().equals(mActivity.getPackageName())
3425                         && event.getClassName().equals(EditText.class.getName())
3426                         && event.getText().size() > 0
3427                         && event.getText().get(0).toString().equals(getString(
3428                                 R.string.android_wiki_paragraphs))
3429                         && event.getFromIndex() == 33
3430                         && event.getToIndex() == 47
3431                         && event.getMovementGranularity() ==
3432                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
3433             }
3434         }, DEFAULT_TIMEOUT_MS);
3435 
3436         // Make sure we got the expected event.
3437         assertNotNull(fourthExpected);
3438 
3439         // Verify the selection position.
3440         assertEquals(2, Selection.getSelectionStart(editText.getText()));
3441         assertEquals(33, Selection.getSelectionEnd(editText.getText()));
3442 
3443         // Move to the previous paragraph and wait for an event.
3444         AccessibilityEvent fifthExpected = sUiAutomation
3445                 .executeAndWaitForEvent(new Runnable() {
3446             @Override
3447             public void run() {
3448                 text.performAction(
3449                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
3450             }
3451         }, new UiAutomation.AccessibilityEventFilter() {
3452             @Override
3453             public boolean accept(AccessibilityEvent event) {
3454                 return
3455                 (event.getEventType() ==
3456                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
3457                         && event.getAction() ==
3458                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
3459                         && event.getPackageName().equals(mActivity.getPackageName())
3460                         && event.getClassName().equals(EditText.class.getName())
3461                         && event.getText().size() > 0
3462                         && event.getText().get(0).toString().equals(getString(
3463                                 R.string.android_wiki_paragraphs))
3464                         && event.getFromIndex() == 16
3465                         && event.getToIndex() == 32
3466                         && event.getMovementGranularity() ==
3467                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
3468             }
3469         }, DEFAULT_TIMEOUT_MS);
3470 
3471         // Make sure we got the expected event.
3472         assertNotNull(fifthExpected);
3473 
3474         // Verify the selection position.
3475         assertEquals(2, Selection.getSelectionStart(editText.getText()));
3476         assertEquals(16, Selection.getSelectionEnd(editText.getText()));
3477 
3478         // Move to the previous paragraph and wait for an event.
3479         AccessibilityEvent sixthExpected = sUiAutomation
3480                 .executeAndWaitForEvent(new Runnable() {
3481             @Override
3482             public void run() {
3483                 text.performAction(
3484                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
3485             }
3486         }, new UiAutomation.AccessibilityEventFilter() {
3487             @Override
3488             public boolean accept(AccessibilityEvent event) {
3489                 return
3490                 (event.getEventType() ==
3491                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
3492                         && event.getAction() ==
3493                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
3494                         && event.getPackageName().equals(mActivity.getPackageName())
3495                         && event.getClassName().equals(EditText.class.getName())
3496                         && event.getText().size() > 0
3497                         && event.getText().get(0).toString().equals(getString(
3498                                 R.string.android_wiki_paragraphs))
3499                         && event.getFromIndex() == 2
3500                         && event.getToIndex() == 14
3501                         && event.getMovementGranularity() ==
3502                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
3503             }
3504         }, DEFAULT_TIMEOUT_MS);
3505 
3506         // Make sure we got the expected event.
3507         assertNotNull(sixthExpected);
3508 
3509         // Verify the selection position.
3510         assertEquals(2, Selection.getSelectionStart(editText.getText()));
3511         assertEquals(2, Selection.getSelectionEnd(editText.getText()));
3512 
3513         // Make sure there is no previous.
3514         assertFalse(text.performAction(
3515                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
3516 
3517         // Verify the selection position.
3518         assertEquals(2, Selection.getSelectionStart(editText.getText()));
3519         assertEquals(2, Selection.getSelectionEnd(editText.getText()));
3520 
3521         // Focus the view so we can change selection.
3522         sInstrumentation.runOnMainSync(new Runnable() {
3523             @Override
3524             public void run() {
3525                 editText.setFocusable(true);
3526                 editText.requestFocus();
3527             }
3528         });
3529 
3530         // Put selection at the end of the text.
3531         Bundle setSelectionArgs = new Bundle();
3532         setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 47);
3533         setSelectionArgs.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 47);
3534         assertTrue(text.performAction(
3535                 AccessibilityNodeInfo.ACTION_SET_SELECTION, setSelectionArgs));
3536 
3537         // Verify the selection position.
3538         assertEquals(47, Selection.getSelectionStart(editText.getText()));
3539         assertEquals(47, Selection.getSelectionEnd(editText.getText()));
3540 
3541         // Move to the previous paragraph and wait for an event.
3542         AccessibilityEvent seventhExpected = sUiAutomation
3543                 .executeAndWaitForEvent(new Runnable() {
3544             @Override
3545             public void run() {
3546                 text.performAction(
3547                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
3548             }
3549         }, new UiAutomation.AccessibilityEventFilter() {
3550             @Override
3551             public boolean accept(AccessibilityEvent event) {
3552                 return
3553                 (event.getEventType() ==
3554                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
3555                         && event.getAction() ==
3556                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
3557                         && event.getPackageName().equals(mActivity.getPackageName())
3558                         && event.getClassName().equals(EditText.class.getName())
3559                         && event.getText().size() > 0
3560                         && event.getText().get(0).toString().equals(getString(
3561                                 R.string.android_wiki_paragraphs))
3562                         && event.getFromIndex() == 33
3563                         && event.getToIndex() == 47
3564                         && event.getMovementGranularity() ==
3565                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
3566             }
3567         }, DEFAULT_TIMEOUT_MS);
3568 
3569         // Make sure we got the expected event.
3570         assertNotNull(seventhExpected);
3571 
3572         // Verify the selection position.
3573         assertEquals(47, Selection.getSelectionStart(editText.getText()));
3574         assertEquals(33, Selection.getSelectionEnd(editText.getText()));
3575 
3576         // Move to the previous paragraph and wait for an event.
3577         AccessibilityEvent eightExpected = sUiAutomation
3578                 .executeAndWaitForEvent(new Runnable() {
3579             @Override
3580             public void run() {
3581                 text.performAction(
3582                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
3583             }
3584         }, new UiAutomation.AccessibilityEventFilter() {
3585             @Override
3586             public boolean accept(AccessibilityEvent event) {
3587                 return
3588                 (event.getEventType() ==
3589                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
3590                         && event.getAction() ==
3591                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
3592                         && event.getPackageName().equals(mActivity.getPackageName())
3593                         && event.getClassName().equals(EditText.class.getName())
3594                         && event.getText().size() > 0
3595                         && event.getText().get(0).toString().equals(getString(
3596                                 R.string.android_wiki_paragraphs))
3597                         && event.getFromIndex() == 16
3598                         && event.getToIndex() == 32
3599                         && event.getMovementGranularity() ==
3600                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
3601             }
3602         }, DEFAULT_TIMEOUT_MS);
3603 
3604         // Make sure we got the expected event.
3605         assertNotNull(eightExpected);
3606 
3607         // Verify the selection position.
3608         assertEquals(47, Selection.getSelectionStart(editText.getText()));
3609         assertEquals(16, Selection.getSelectionEnd(editText.getText()));
3610 
3611         // Move to the previous paragraph and wait for an event.
3612         AccessibilityEvent ninethExpected = sUiAutomation
3613                 .executeAndWaitForEvent(new Runnable() {
3614             @Override
3615             public void run() {
3616                 text.performAction(
3617                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments);
3618             }
3619         }, new UiAutomation.AccessibilityEventFilter() {
3620             @Override
3621             public boolean accept(AccessibilityEvent event) {
3622                 return
3623                 (event.getEventType() ==
3624                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
3625                         && event.getAction() ==
3626                                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
3627                         && event.getPackageName().equals(mActivity.getPackageName())
3628                         && event.getClassName().equals(EditText.class.getName())
3629                         && event.getText().size() > 0
3630                         && event.getText().get(0).toString().equals(getString(
3631                                 R.string.android_wiki_paragraphs))
3632                         && event.getFromIndex() == 2
3633                         && event.getToIndex() == 14
3634                         && event.getMovementGranularity() ==
3635                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
3636             }
3637         }, DEFAULT_TIMEOUT_MS);
3638 
3639         // Make sure we got the expected event.
3640         assertNotNull(ninethExpected);
3641 
3642         // Verify the selection position.
3643         assertEquals(47, Selection.getSelectionStart(editText.getText()));
3644         assertEquals(2, Selection.getSelectionEnd(editText.getText()));
3645 
3646         // Make sure there is no previous.
3647         assertFalse(text.performAction(
3648                 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, arguments));
3649 
3650         // Verify the selection position.
3651         assertEquals(47, Selection.getSelectionStart(editText.getText()));
3652         assertEquals(2, Selection.getSelectionEnd(editText.getText()));
3653 
3654         // Move to the next paragraph and wait for an event.
3655         AccessibilityEvent tenthExpected = sUiAutomation
3656                 .executeAndWaitForEvent(new Runnable() {
3657             @Override
3658             public void run() {
3659                 text.performAction(
3660                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
3661             }
3662         }, new UiAutomation.AccessibilityEventFilter() {
3663             @Override
3664             public boolean accept(AccessibilityEvent event) {
3665                 return
3666                 (event.getEventType() ==
3667                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
3668                         && event.getAction() ==
3669                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
3670                         && event.getPackageName().equals(mActivity.getPackageName())
3671                         && event.getClassName().equals(EditText.class.getName())
3672                         && event.getText().size() > 0
3673                         && event.getText().get(0).toString().equals(getString(
3674                                 R.string.android_wiki_paragraphs))
3675                         && event.getFromIndex() == 2
3676                         && event.getToIndex() == 14
3677                         && event.getMovementGranularity() ==
3678                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
3679             }
3680         }, DEFAULT_TIMEOUT_MS);
3681 
3682         // Make sure we got the expected event.
3683         assertNotNull(tenthExpected);
3684 
3685         // Verify the selection position.
3686         assertEquals(47, Selection.getSelectionStart(editText.getText()));
3687         assertEquals(14, Selection.getSelectionEnd(editText.getText()));
3688 
3689         // Move to the next paragraph and wait for an event.
3690         AccessibilityEvent eleventhExpected = sUiAutomation
3691                 .executeAndWaitForEvent(new Runnable() {
3692             @Override
3693             public void run() {
3694                 text.performAction(
3695                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
3696             }
3697         }, new UiAutomation.AccessibilityEventFilter() {
3698             @Override
3699             public boolean accept(AccessibilityEvent event) {
3700                 return
3701                 (event.getEventType() ==
3702                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
3703                         && event.getAction() ==
3704                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
3705                         && event.getPackageName().equals(mActivity.getPackageName())
3706                         && event.getClassName().equals(EditText.class.getName())
3707                         && event.getText().size() > 0
3708                         && event.getText().get(0).toString().equals(getString(
3709                                 R.string.android_wiki_paragraphs))
3710                         && event.getFromIndex() == 16
3711                         && event.getToIndex() == 32
3712                         && event.getMovementGranularity() ==
3713                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
3714             }
3715         }, DEFAULT_TIMEOUT_MS);
3716 
3717         // Make sure we got the expected event.
3718         assertNotNull(eleventhExpected);
3719 
3720         // Verify the selection position.
3721         assertEquals(47, Selection.getSelectionStart(editText.getText()));
3722         assertEquals(32, Selection.getSelectionEnd(editText.getText()));
3723 
3724         // Move to the next paragraph and wait for an event.
3725         AccessibilityEvent twlevethExpected = sUiAutomation
3726                 .executeAndWaitForEvent(new Runnable() {
3727             @Override
3728             public void run() {
3729                 text.performAction(
3730                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
3731             }
3732         }, new UiAutomation.AccessibilityEventFilter() {
3733             @Override
3734             public boolean accept(AccessibilityEvent event) {
3735                 return
3736                 (event.getEventType() ==
3737                     AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
3738                         && event.getAction() ==
3739                                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
3740                         && event.getPackageName().equals(mActivity.getPackageName())
3741                         && event.getClassName().equals(EditText.class.getName())
3742                         && event.getText().size() > 0
3743                         && event.getText().get(0).toString().equals(getString(
3744                                 R.string.android_wiki_paragraphs))
3745                         && event.getFromIndex() == 33
3746                         && event.getToIndex() == 47
3747                         && event.getMovementGranularity() ==
3748                                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
3749             }
3750         }, DEFAULT_TIMEOUT_MS);
3751 
3752         // Make sure we got the expected event.
3753         assertNotNull(twlevethExpected);
3754 
3755         // Verify the selection position.
3756         assertEquals(47, Selection.getSelectionStart(editText.getText()));
3757         assertEquals(47, Selection.getSelectionEnd(editText.getText()));
3758 
3759         // Make sure there is no next.
3760         assertFalse(text.performAction(
3761                 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments));
3762 
3763         // Verify the selection position.
3764         assertEquals(47, Selection.getSelectionStart(editText.getText()));
3765         assertEquals(47, Selection.getSelectionEnd(editText.getText()));
3766     }
3767 
3768     @MediumTest
3769     @Test
testTextEditingActions()3770     public void testTextEditingActions() throws Exception {
3771         if (!mActivity.getPackageManager().hasSystemFeature(
3772                 PackageManager.FEATURE_INPUT_METHODS)) {
3773             return;
3774         }
3775 
3776         final EditText editText = (EditText) mActivity.findViewById(R.id.edit);
3777         final String textContent = getString(R.string.foo_bar_baz);
3778 
3779         sInstrumentation.runOnMainSync(new Runnable() {
3780             @Override
3781             public void run() {
3782                 editText.setVisibility(View.VISIBLE);
3783                 editText.setFocusable(true);
3784                 editText.requestFocus();
3785                 editText.setText(getString(R.string.foo_bar_baz));
3786                 Selection.removeSelection(editText.getText());
3787             }
3788         });
3789 
3790         final AccessibilityNodeInfo text = sUiAutomation
3791                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
3792                        getString(R.string.foo_bar_baz)).get(0);
3793 
3794         // Select all text.
3795         Bundle arguments = new Bundle();
3796         arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 0);
3797         arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT,
3798                 editText.getText().length());
3799         assertTrue(text.performAction(
3800                 AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments));
3801 
3802         // Copy the selected text.
3803         text.performAction(AccessibilityNodeInfo.ACTION_COPY);
3804 
3805         // Set selection at the end.
3806         final int textLength = editText.getText().length();
3807         arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, textLength);
3808         arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, textLength);
3809         // Don't check the return value, because the copy action could move the selection and the
3810         // operation will fail if the selection is already at the end.
3811         text.performAction(AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments);
3812 
3813         // Verify the selection position.
3814         assertEquals(textLength, Selection.getSelectionStart(editText.getText()));
3815         assertEquals(textLength, Selection.getSelectionEnd(editText.getText()));
3816 
3817         // Paste the selected text.
3818         assertTrue(text.performAction(
3819                 AccessibilityNodeInfo.ACTION_PASTE));
3820 
3821         // Verify the content.
3822         assertEquals(editText.getText().toString(), textContent + textContent);
3823 
3824         // Select all text.
3825         arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 0);
3826         arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT,
3827                 editText.getText().length());
3828         assertTrue(text.performAction(
3829                 AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments));
3830 
3831         // Cut the selected text.
3832         assertTrue(text.performAction(
3833                 AccessibilityNodeInfo.ACTION_CUT));
3834 
3835         // Verify the content.
3836         assertTrue(TextUtils.isEmpty(editText.getText()));
3837     }
3838 
3839     @Test
testSetSelectionInContentDescription()3840     public void testSetSelectionInContentDescription() throws Exception {
3841         final View view = mActivity.findViewById(R.id.view);
3842 
3843         sInstrumentation.runOnMainSync(new Runnable() {
3844             @Override
3845             public void run() {
3846                 view.setVisibility(View.VISIBLE);
3847                 view.setContentDescription(getString(R.string.foo_bar_baz));
3848             }
3849         });
3850 
3851         AccessibilityNodeInfo text = sUiAutomation
3852                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
3853                        getString(R.string.foo_bar_baz)).get(0);
3854 
3855         // Set the cursor position.
3856         Bundle arguments = new Bundle();
3857         arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 4);
3858         arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 4);
3859         assertTrue(text.performAction(
3860                 AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments));
3861 
3862         // Try and fail to set the selection longer than zero.
3863         arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 4);
3864         arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 5);
3865         assertFalse(text.performAction(
3866                 AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments));
3867     }
3868 
3869     @Test
testSelectionPositionForNonEditableView()3870     public void testSelectionPositionForNonEditableView() throws Exception {
3871         final View view = mActivity.findViewById(R.id.view);
3872 
3873         sInstrumentation.runOnMainSync(new Runnable() {
3874             @Override
3875             public void run() {
3876                 view.setVisibility(View.VISIBLE);
3877                 view.setContentDescription(getString(R.string.foo_bar_baz));
3878             }
3879         });
3880 
3881         final AccessibilityNodeInfo text = sUiAutomation
3882                .getRootInActiveWindow().findAccessibilityNodeInfosByText(
3883                        getString(R.string.foo_bar_baz)).get(0);
3884 
3885         // Check the initial node properties.
3886         assertFalse(text.isEditable());
3887         assertSame(text.getTextSelectionStart(), -1);
3888         assertSame(text.getTextSelectionEnd(), -1);
3889 
3890         // Set the cursor position.
3891         sUiAutomation.executeAndWaitForEvent(new Runnable() {
3892             @Override
3893             public void run() {
3894                 Bundle arguments = new Bundle();
3895                 arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 4);
3896                 arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 4);
3897                 assertTrue(text.performAction(
3898                         AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments));
3899             }
3900         }, new UiAutomation.AccessibilityEventFilter() {
3901             @Override
3902             public boolean accept(AccessibilityEvent event) {
3903                 return (event.getEventType()
3904                         == AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED);
3905             }
3906         }, DEFAULT_TIMEOUT_MS);
3907 
3908         // Refresh the node.
3909         AccessibilityNodeInfo refreshedText = sUiAutomation
3910                 .getRootInActiveWindow().findAccessibilityNodeInfosByText(
3911                         getString(R.string.foo_bar_baz)).get(0);
3912 
3913         // Check the related node properties.
3914         assertFalse(refreshedText.isEditable());
3915         assertSame(refreshedText.getTextSelectionStart(), 4);
3916         assertSame(refreshedText.getTextSelectionEnd(), 4);
3917 
3918         // Try to set to an invalid cursor position.
3919         Bundle arguments = new Bundle();
3920         arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 4);
3921         arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 5);
3922         assertFalse(text.performAction(
3923                 AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments));
3924 
3925         // Refresh the node.
3926         refreshedText = sUiAutomation
3927                 .getRootInActiveWindow().findAccessibilityNodeInfosByText(
3928                         getString(R.string.foo_bar_baz)).get(0);
3929 
3930         // Check the related node properties.
3931         assertFalse(refreshedText.isEditable());
3932         assertSame(refreshedText.getTextSelectionStart(), 4);
3933         assertSame(refreshedText.getTextSelectionEnd(), 4);
3934     }
3935 
3936     @Test
testViewDoesNotHaveSelectableText()3937     public void testViewDoesNotHaveSelectableText() {
3938         final TextView nonSelectableView = mActivity.findViewById(R.id.text);
3939 
3940         sInstrumentation.runOnMainSync(() -> {
3941             nonSelectableView.setVisibility(View.VISIBLE);
3942             nonSelectableView.setText(getString(R.string.a_b));
3943 
3944         });
3945 
3946         final AccessibilityNodeInfo textNode = sUiAutomation
3947                 .getRootInActiveWindow().findAccessibilityNodeInfosByText(
3948                         getString(R.string.a_b)).get(0);
3949 
3950         assertFalse("Text node has selectable text.", textNode.isTextSelectable());
3951     }
3952 
3953     @Test
testViewDoesHaveSelectableText()3954     public void testViewDoesHaveSelectableText() {
3955         final TextView selectableView = mActivity.findViewById(R.id.selectableText);
3956         final EditText editText = mActivity.findViewById(R.id.editText);
3957 
3958         sInstrumentation.runOnMainSync(() -> {
3959             selectableView.setVisibility(View.VISIBLE);
3960             selectableView.setText(getString(R.string.a_b));
3961             editText.setVisibility(View.VISIBLE);
3962             editText.setText(getString(R.string.foo_bar_baz));
3963         });
3964 
3965         final AccessibilityNodeInfo selectableTextNode = sUiAutomation
3966                 .getRootInActiveWindow().findAccessibilityNodeInfosByText(
3967                         getString(R.string.a_b)).get(0);
3968 
3969         final AccessibilityNodeInfo editTextNode = sUiAutomation
3970                 .getRootInActiveWindow().findAccessibilityNodeInfosByText(
3971                         getString(R.string.foo_bar_baz)).get(0);
3972 
3973         assertTrue("Text node does not have selectable text.",
3974                 selectableTextNode.isTextSelectable());
3975 
3976         assertTrue("EditText node does not have selectable text.", editTextNode.isTextSelectable());
3977     }
3978 
3979     @Test
testSelectionMovesFocus()3980     public void testSelectionMovesFocus() throws Exception {
3981         final TextView selectableView = mActivity.findViewById(R.id.selectableText);
3982         final EditText editText = mActivity.findViewById(R.id.editText);
3983 
3984         sInstrumentation.runOnMainSync(() -> {
3985             selectableView.setVisibility(View.VISIBLE);
3986             selectableView.setText(getString(R.string.a_b));
3987             editText.setVisibility(View.VISIBLE);
3988             editText.setText(getString(R.string.foo_bar_baz));
3989             editText.setFocusable(true);
3990             editText.requestFocus();
3991         });
3992 
3993         AccessibilityNodeInfo selectableTextNode = sUiAutomation
3994                 .getRootInActiveWindow().findAccessibilityNodeInfosByText(
3995                         getString(R.string.a_b)).get(0);
3996 
3997         final AccessibilityNodeInfo editTextNode = sUiAutomation
3998                 .getRootInActiveWindow().findAccessibilityNodeInfosByText(
3999                         getString(R.string.foo_bar_baz)).get(0);
4000 
4001         assertTrue("Selectable text node does not have selectable text.",
4002                 selectableTextNode.isTextSelectable());
4003 
4004         assertTrue("EditText node does not have selectable text.",
4005                 editTextNode.isTextSelectable());
4006 
4007         assertTrue("EditText is not focused", editTextNode.isFocused());
4008 
4009         performMovementActionAndGetEvent(selectableTextNode,
4010                 AccessibilityNodeInfo.AccessibilityAction.ACTION_NEXT_AT_MOVEMENT_GRANULARITY,
4011                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER, true);
4012 
4013         // Refresh node.
4014         selectableTextNode = sUiAutomation
4015                 .getRootInActiveWindow().findAccessibilityNodeInfosByText(
4016                         getString(R.string.a_b)).get(0);
4017 
4018         assertTrue("Selectable text node does not get focus after selection",
4019                 selectableTextNode.isFocused());
4020     }
4021 
4022     @Test
testSelectionDoesNotMoveFocus()4023     public void testSelectionDoesNotMoveFocus() throws Exception {
4024         final TextView selectableView = mActivity.findViewById(R.id.selectableText);
4025         final EditText editText = mActivity.findViewById(R.id.editText);
4026 
4027         sInstrumentation.runOnMainSync(() -> {
4028             selectableView.setVisibility(View.VISIBLE);
4029             selectableView.setText(getString(R.string.a_b));
4030             selectableView.setTextIsSelectable(false);
4031             editText.setVisibility(View.VISIBLE);
4032             editText.setText(getString(R.string.foo_bar_baz));
4033             editText.setFocusable(true);
4034             editText.requestFocus();
4035         });
4036 
4037         AccessibilityNodeInfo selectableTextNode = sUiAutomation
4038                 .getRootInActiveWindow().findAccessibilityNodeInfosByText(
4039                         getString(R.string.a_b)).get(0);
4040 
4041         final AccessibilityNodeInfo editTextNode = sUiAutomation
4042                 .getRootInActiveWindow().findAccessibilityNodeInfosByText(
4043                         getString(R.string.foo_bar_baz)).get(0);
4044 
4045         assertFalse("Selectable text node does have selectable text.",
4046                 selectableTextNode.isTextSelectable());
4047 
4048         assertTrue("EditText node does not have selectable text.",
4049                 editTextNode.isTextSelectable());
4050 
4051         assertTrue("EditText is not focused", editTextNode.isFocused());
4052 
4053         performMovementActionAndGetEvent(selectableTextNode,
4054                 AccessibilityNodeInfo.AccessibilityAction.ACTION_NEXT_AT_MOVEMENT_GRANULARITY,
4055                 AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER, true);
4056 
4057         // Refresh node.
4058         selectableTextNode = sUiAutomation
4059                 .getRootInActiveWindow().findAccessibilityNodeInfosByText(
4060                         getString(R.string.a_b)).get(0);
4061 
4062         assertFalse("Selectable text node gets focus after selection",
4063                 selectableTextNode.isFocused());
4064     }
4065 
performMovementActionAndGetEvent(final AccessibilityNodeInfo target, AccessibilityNodeInfo.AccessibilityAction action, final int granularity, final boolean extendSelection)4066     private AccessibilityEvent performMovementActionAndGetEvent(final AccessibilityNodeInfo target,
4067             AccessibilityNodeInfo.AccessibilityAction action, final int granularity,
4068             final boolean extendSelection)
4069             throws Exception {
4070         final Bundle arguments = new Bundle();
4071         arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
4072                 granularity);
4073         if (extendSelection) {
4074             arguments.putBoolean(
4075                     AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, true);
4076         }
4077         Runnable performActionRunnable = () -> target.performAction(action.getId(), arguments);
4078         UiAutomation.AccessibilityEventFilter filter = event -> {
4079             boolean isMovementEvent = event.getEventType()
4080                     == AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY;
4081             boolean actionMatches = event.getAction() == action.getId();
4082             boolean packageMatches = TextUtils.equals(event.getPackageName(),
4083                     mActivity.getPackageName());
4084             boolean granularityMatches = event.getMovementGranularity() == granularity;
4085             return isMovementEvent && actionMatches && packageMatches && granularityMatches;
4086         };
4087         return sUiAutomation
4088                 .executeAndWaitForEvent(performActionRunnable, filter, DEFAULT_TIMEOUT_MS);
4089     }
4090 
getString(int id)4091     private String getString(int id) {
4092         return mActivity.getString(id);
4093     }
4094 }
4095