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