AccessibilityManagerServiceTest.java revision 5637745e59e1c0c22ec2e0adb1f48f8f4edcb7be
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
19import android.accessibilityservice.AccessibilityService;
20import android.accessibilityservice.AccessibilityServiceInfo;
21import android.content.ComponentName;
22import android.content.Context;
23import android.content.pm.ServiceInfo;
24import android.os.IBinder;
25import android.os.Message;
26import android.os.ServiceManager;
27import android.os.SystemClock;
28import android.provider.Settings;
29import android.test.AndroidTestCase;
30import android.test.suitebuilder.annotation.LargeTest;
31import android.view.accessibility.AccessibilityEvent;
32import android.view.accessibility.IAccessibilityManager;
33import android.view.accessibility.IAccessibilityManagerClient;
34
35/**
36 * This test exercises the
37 * {@link com.android.server.AccessibilityManagerService} by mocking the
38 * {@link android.view.accessibility.AccessibilityManager} which talks to to the
39 * service. The service itself is interacting with the platform. Note: Testing
40 * the service in full isolation would require significant amount of work for
41 * mocking all system interactions. It would also require a lot of mocking code.
42 */
43public class AccessibilityManagerServiceTest extends AndroidTestCase {
44
45    /**
46     * Timeout required for pending Binder calls or event processing to
47     * complete.
48     */
49    private static final long TIMEOUT_BINDER_CALL = 100;
50
51    /**
52     * Timeout in which we are waiting for the system to start the mock
53     * accessibility services.
54     */
55    private static final long TIMEOUT_START_MOCK_ACCESSIBILITY_SERVICES = 300;
56
57    /**
58     * Timeout used for testing that a service is notified only upon a
59     * notification timeout.
60     */
61    private static final long TIMEOUT_TEST_NOTIFICATION_TIMEOUT = 300;
62
63    /**
64     * The package name.
65     */
66    private static String sPackageName;
67
68    /**
69     * The interface used to talk to the tested service.
70     */
71    private IAccessibilityManager mManagerService;
72
73    @Override
74    public void setContext(Context context) {
75        super.setContext(context);
76        if (sPackageName == null) {
77            sPackageName = context.getPackageName();
78        }
79    }
80
81    /**
82     * Creates a new instance.
83     */
84    public AccessibilityManagerServiceTest() {
85        IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
86        mManagerService = IAccessibilityManager.Stub.asInterface(iBinder);
87    }
88
89    @LargeTest
90    public void testAddClient_AccessibilityDisabledThenEnabled() throws Exception {
91        // make sure accessibility is disabled
92        ensureAccessibilityEnabled(mContext, false);
93
94        // create a client mock instance
95        MyMockAccessibilityManagerClient mockClient = new MyMockAccessibilityManagerClient();
96
97        // invoke the method under test
98        boolean enabledAccessibilityDisabled = mManagerService.addClient(mockClient);
99
100        // check expected result
101        assertFalse("The client must be disabled since accessibility is disabled.",
102                enabledAccessibilityDisabled);
103
104        // enable accessibility
105        ensureAccessibilityEnabled(mContext, true);
106
107        // invoke the method under test
108        boolean enabledAccessibilityEnabled = mManagerService.addClient(mockClient);
109
110        // check expected result
111        assertTrue("The client must be enabled since accessibility is enabled.",
112                enabledAccessibilityEnabled);
113    }
114
115    @LargeTest
116    public void testAddClient_AccessibilityEnabledThenDisabled() throws Exception {
117        // enable accessibility before registering the client
118        ensureAccessibilityEnabled(mContext, true);
119
120        // create a client mock instance
121        MyMockAccessibilityManagerClient mockClient = new MyMockAccessibilityManagerClient();
122
123        // invoke the method under test
124        boolean enabledAccessibilityEnabled = mManagerService.addClient(mockClient);
125
126        // check expected result
127        assertTrue("The client must be enabled since accessibility is enabled.",
128                enabledAccessibilityEnabled);
129
130        // disable accessibility
131        ensureAccessibilityEnabled(mContext, false);
132
133        // invoke the method under test
134        boolean enabledAccessibilityDisabled = mManagerService.addClient(mockClient);
135
136        // check expected result
137        assertFalse("The client must be disabled since accessibility is disabled.",
138                enabledAccessibilityDisabled);
139    }
140
141    @LargeTest
142    public void testGetAccessibilityServicesList() throws Exception {
143        boolean firstMockServiceInstalled = false;
144        boolean secondMockServiceInstalled = false;
145
146        String packageName = getContext().getPackageName();
147        String firstMockServiceClassName = MyFirstMockAccessibilityService.class.getName();
148        String secondMockServiceClassName = MySecondMockAccessibilityService.class.getName();
149
150        // look for the two mock services
151        for (ServiceInfo serviceInfo : mManagerService.getAccessibilityServiceList()) {
152            if (packageName.equals(serviceInfo.packageName)) {
153                if (firstMockServiceClassName.equals(serviceInfo.name)) {
154                    firstMockServiceInstalled = true;
155                } else if (secondMockServiceClassName.equals(serviceInfo.name)) {
156                    secondMockServiceInstalled = true;
157                }
158            }
159        }
160
161        // check expected result
162        assertTrue("First mock service must be installed", firstMockServiceInstalled);
163        assertTrue("Second mock service must be installed", secondMockServiceInstalled);
164    }
165
166    @LargeTest
167    public void testSendAccessibilityEvent_OneService_MatchingPackageAndEventType()
168            throws Exception {
169        // set the accessibility setting value
170        ensureAccessibilityEnabled(mContext, true);
171
172        // enable the mock accessibility service
173        ensureOnlyMockServicesEnabled(mContext, true, false);
174
175        // configure the mock service
176        MockAccessibilityService service = MyFirstMockAccessibilityService.sInstance;
177        service.setServiceInfo(MockAccessibilityService.createDefaultInfo());
178
179        // wait for the binder call to #setService to complete
180        Thread.sleep(TIMEOUT_BINDER_CALL);
181
182        // create and populate an event to be sent
183        AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
184        fullyPopulateDefaultAccessibilityEvent(sentEvent);
185
186        // set expectations
187        service.expectEvent(sentEvent);
188        service.replay();
189
190        // send the event
191        mManagerService.sendAccessibilityEvent(sentEvent);
192
193        // verify if all expected methods have been called
194        assertMockServiceVerifiedWithinTimeout(service);
195    }
196
197    @LargeTest
198    public void testSendAccessibilityEvent_OneService_NotMatchingPackage() throws Exception {
199        // set the accessibility setting value
200        ensureAccessibilityEnabled(mContext, true);
201
202        // enable the mock accessibility service
203        ensureOnlyMockServicesEnabled(mContext, true, false);
204
205        // configure the mock service
206        MockAccessibilityService service = MyFirstMockAccessibilityService.sInstance;
207        service.setServiceInfo(MockAccessibilityService.createDefaultInfo());
208
209        // wait for the binder call to #setService to complete
210        Thread.sleep(TIMEOUT_BINDER_CALL);
211
212        // create and populate an event to be sent
213        AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
214        fullyPopulateDefaultAccessibilityEvent(sentEvent);
215        sentEvent.setPackageName("no.service.registered.for.this.package");
216
217        // set expectations
218        service.replay();
219
220        // send the event
221        mManagerService.sendAccessibilityEvent(sentEvent);
222
223        // verify if all expected methods have been called
224        assertMockServiceVerifiedWithinTimeout(service);
225    }
226
227    @LargeTest
228    public void testSendAccessibilityEvent_OneService_NotMatchingEventType() throws Exception {
229        // set the accessibility setting value
230        ensureAccessibilityEnabled(mContext, true);
231
232        // enable the mock accessibility service
233        ensureOnlyMockServicesEnabled(mContext, true, false);
234
235        // configure the mock service
236        MockAccessibilityService service = MyFirstMockAccessibilityService.sInstance;
237        service.setServiceInfo(MockAccessibilityService.createDefaultInfo());
238
239        // wait for the binder call to #setService to complete
240        Thread.sleep(TIMEOUT_BINDER_CALL);
241
242        // create and populate an event to be sent
243        AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
244        fullyPopulateDefaultAccessibilityEvent(sentEvent);
245        sentEvent.setEventType(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
246
247        // set expectations
248        service.replay();
249
250        // send the event
251        mManagerService.sendAccessibilityEvent(sentEvent);
252
253        // verify if all expected methods have been called
254        assertMockServiceVerifiedWithinTimeout(service);
255    }
256
257    @LargeTest
258    public void testSendAccessibilityEvent_OneService_NotifivationAfterTimeout() throws Exception {
259        // set the accessibility setting value
260        ensureAccessibilityEnabled(mContext, true);
261
262        // enable the mock accessibility service
263        ensureOnlyMockServicesEnabled(mContext, true, false);
264
265        // configure the mock service
266        MockAccessibilityService service = MyFirstMockAccessibilityService.sInstance;
267        AccessibilityServiceInfo info = MockAccessibilityService.createDefaultInfo();
268        info.notificationTimeout = TIMEOUT_TEST_NOTIFICATION_TIMEOUT;
269        service.setServiceInfo(info);
270
271        // wait for the binder call to #setService to complete
272        Thread.sleep(TIMEOUT_BINDER_CALL);
273
274        // create and populate the first event to be sent
275        AccessibilityEvent firstEvent = AccessibilityEvent.obtain();
276        fullyPopulateDefaultAccessibilityEvent(firstEvent);
277
278        // create and populate the second event to be sent
279        AccessibilityEvent secondEvent = AccessibilityEvent.obtain();
280        fullyPopulateDefaultAccessibilityEvent(secondEvent);
281
282        // set expectations
283        service.expectEvent(secondEvent);
284        service.replay();
285
286        // send the events
287        mManagerService.sendAccessibilityEvent(firstEvent);
288        mManagerService.sendAccessibilityEvent(secondEvent);
289
290        // wait for #sendAccessibilityEvent to reach the backing service
291        Thread.sleep(TIMEOUT_BINDER_CALL);
292
293        try {
294            service.verify();
295            fail("No events must be dispatched before the expiration of the notification timeout.");
296        } catch (IllegalStateException ise) {
297            /* expected */
298        }
299
300        // wait for the configured notification timeout to expire
301        Thread.sleep(TIMEOUT_TEST_NOTIFICATION_TIMEOUT);
302
303        // verify if all expected methods have been called
304        assertMockServiceVerifiedWithinTimeout(service);
305    }
306
307    @LargeTest
308    public void testSendAccessibilityEvent_TwoServices_MatchingPackageAndEventType_DiffFeedback()
309            throws Exception {
310        // set the accessibility setting value
311        ensureAccessibilityEnabled(mContext, true);
312
313        // enable the mock accessibility services
314        ensureOnlyMockServicesEnabled(mContext, true, true);
315
316        // configure the first mock service
317        MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance;
318        AccessibilityServiceInfo firstInfo = MockAccessibilityService.createDefaultInfo();
319        firstInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_AUDIBLE;
320        firstService.setServiceInfo(firstInfo);
321
322        // configure the second mock service
323        MockAccessibilityService secondService = MySecondMockAccessibilityService.sInstance;
324        AccessibilityServiceInfo secondInfo = MockAccessibilityService.createDefaultInfo();
325        secondInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_HAPTIC;
326        secondService.setServiceInfo(secondInfo);
327
328        // wait for the binder calls to #setService to complete
329        Thread.sleep(TIMEOUT_BINDER_CALL);
330
331        // create and populate an event to be sent
332        AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
333        fullyPopulateDefaultAccessibilityEvent(sentEvent);
334
335        // set expectations for the first mock service
336        firstService.expectEvent(sentEvent);
337        firstService.replay();
338
339        // set expectations for the second mock service
340        secondService.expectEvent(sentEvent);
341        secondService.replay();
342
343        // send the event
344        mManagerService.sendAccessibilityEvent(sentEvent);
345
346        // verify if all expected methods have been called
347        assertMockServiceVerifiedWithinTimeout(firstService);
348        assertMockServiceVerifiedWithinTimeout(secondService);
349    }
350
351    @LargeTest
352    public void testSendAccessibilityEvent_TwoServices_MatchingPackageAndEventType()
353            throws Exception {
354        // set the accessibility setting value
355        ensureAccessibilityEnabled(mContext, true);
356
357        // enable the mock accessibility services
358        ensureOnlyMockServicesEnabled(mContext, true, true);
359
360        // configure the first mock service
361        MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance;
362        firstService.setServiceInfo(MockAccessibilityService.createDefaultInfo());
363
364        // configure the second mock service
365        MockAccessibilityService secondService = MySecondMockAccessibilityService.sInstance;
366        secondService.setServiceInfo(MockAccessibilityService.createDefaultInfo());
367
368        // wait for the binder calls to #setService to complete
369        Thread.sleep(TIMEOUT_BINDER_CALL);
370
371        // create and populate an event to be sent
372        AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
373        fullyPopulateDefaultAccessibilityEvent(sentEvent);
374
375        // set expectations for the first mock service
376        firstService.expectEvent(sentEvent);
377        firstService.replay();
378
379        // set expectations for the second mock service
380        secondService.replay();
381
382        // send the event
383        mManagerService.sendAccessibilityEvent(sentEvent);
384
385        // verify if all expected methods have been called
386        assertMockServiceVerifiedWithinTimeout(firstService);
387        assertMockServiceVerifiedWithinTimeout(secondService);
388    }
389
390    @LargeTest
391    public void testSendAccessibilityEvent_TwoServices_MatchingPackageAndEventType_OneDefault()
392            throws Exception {
393        // set the accessibility setting value
394        ensureAccessibilityEnabled(mContext, true);
395
396        // enable the mock accessibility services
397        ensureOnlyMockServicesEnabled(mContext, true, true);
398
399        // configure the first mock service
400        MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance;
401        AccessibilityServiceInfo firstInfo = MyFirstMockAccessibilityService.createDefaultInfo();
402        firstInfo.flags = AccessibilityServiceInfo.DEFAULT;
403        firstService.setServiceInfo(firstInfo);
404
405        // configure the second mock service
406        MockAccessibilityService secondService = MySecondMockAccessibilityService.sInstance;
407        secondService.setServiceInfo(MySecondMockAccessibilityService.createDefaultInfo());
408
409        // wait for the binder calls to #setService to complete
410        Thread.sleep(TIMEOUT_BINDER_CALL);
411
412        // create and populate an event to be sent
413        AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
414        fullyPopulateDefaultAccessibilityEvent(sentEvent);
415
416        // set expectations for the first mock service
417        firstService.replay();
418
419        // set expectations for the second mock service
420        secondService.expectEvent(sentEvent);
421        secondService.replay();
422
423        // send the event
424        mManagerService.sendAccessibilityEvent(sentEvent);
425
426        // verify if all expected methods have been called
427        assertMockServiceVerifiedWithinTimeout(firstService);
428        assertMockServiceVerifiedWithinTimeout(secondService);
429    }
430
431    @LargeTest
432    public void testSendAccessibilityEvent_TwoServices_MatchingPackageAndEventType_TwoDefault()
433            throws Exception {
434        // set the accessibility setting value
435        ensureAccessibilityEnabled(mContext, true);
436
437        // enable the mock accessibility services
438        ensureOnlyMockServicesEnabled(mContext, true, true);
439
440        // configure the first mock service
441        MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance;
442        AccessibilityServiceInfo firstInfo = MyFirstMockAccessibilityService.createDefaultInfo();
443        firstInfo.flags = AccessibilityServiceInfo.DEFAULT;
444        firstService.setServiceInfo(firstInfo);
445
446        // configure the second mock service
447        MockAccessibilityService secondService = MySecondMockAccessibilityService.sInstance;
448        AccessibilityServiceInfo secondInfo = MyFirstMockAccessibilityService.createDefaultInfo();
449        secondInfo.flags = AccessibilityServiceInfo.DEFAULT;
450        secondService.setServiceInfo(firstInfo);
451
452        // wait for the binder calls to #setService to complete
453        Thread.sleep(TIMEOUT_BINDER_CALL);
454
455        // create and populate an event to be sent
456        AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
457        fullyPopulateDefaultAccessibilityEvent(sentEvent);
458
459        // set expectations for the first mock service
460        firstService.expectEvent(sentEvent);
461        firstService.replay();
462
463        // set expectations for the second mock service
464        secondService.replay();
465
466        // send the event
467        mManagerService.sendAccessibilityEvent(sentEvent);
468
469        // verify if all expected methods have been called
470        assertMockServiceVerifiedWithinTimeout(firstService);
471        assertMockServiceVerifiedWithinTimeout(secondService);
472    }
473
474    @LargeTest
475    public void testInterrupt() throws Exception {
476        // set the accessibility setting value
477        ensureAccessibilityEnabled(mContext, true);
478
479        // enable the mock accessibility services
480        ensureOnlyMockServicesEnabled(mContext, true, true);
481
482        // configure the first mock service
483        MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance;
484        firstService.setServiceInfo(MockAccessibilityService.createDefaultInfo());
485
486        // configure the second mock service
487        MockAccessibilityService secondService = MySecondMockAccessibilityService.sInstance;
488        secondService.setServiceInfo(MockAccessibilityService.createDefaultInfo());
489
490        // wait for the binder calls to #setService to complete
491        Thread.sleep(TIMEOUT_BINDER_CALL);
492
493        // set expectations for the first mock service
494        firstService.expectInterrupt();
495        firstService.replay();
496
497        // set expectations for the second mock service
498        secondService.expectInterrupt();
499        secondService.replay();
500
501        // call the method under test
502        mManagerService.interrupt();
503
504        // verify if all expected methods have been called
505        assertMockServiceVerifiedWithinTimeout(firstService);
506        assertMockServiceVerifiedWithinTimeout(secondService);
507    }
508
509    /**
510     * Fully populates the {@link AccessibilityEvent} to marshal.
511     *
512     * @param sentEvent The event to populate.
513     */
514    private void fullyPopulateDefaultAccessibilityEvent(AccessibilityEvent sentEvent) {
515        sentEvent.setAddedCount(1);
516        sentEvent.setBeforeText("BeforeText");
517        sentEvent.setChecked(true);
518        sentEvent.setClassName("foo.bar.baz.Class");
519        sentEvent.setContentDescription("ContentDescription");
520        sentEvent.setCurrentItemIndex(1);
521        sentEvent.setEnabled(true);
522        sentEvent.setEventType(AccessibilityEvent.TYPE_VIEW_CLICKED);
523        sentEvent.setEventTime(1000);
524        sentEvent.setFromIndex(1);
525        sentEvent.setFullScreen(true);
526        sentEvent.setItemCount(1);
527        sentEvent.setPackageName("foo.bar.baz");
528        sentEvent.setParcelableData(Message.obtain(null, 1, null));
529        sentEvent.setPassword(true);
530        sentEvent.setRemovedCount(1);
531    }
532
533    /**
534     * This class is a mock {@link IAccessibilityManagerClient}.
535     */
536    public class MyMockAccessibilityManagerClient extends IAccessibilityManagerClient.Stub {
537        boolean mIsEnabled;
538
539        public void setEnabled(boolean enabled) {
540            mIsEnabled = enabled;
541        }
542    }
543
544    /**
545     * Ensures accessibility is in a given state by writing the state to the
546     * settings and waiting until the accessibility manager service pick it up.
547     *
548     * @param context A context handle to access the settings.
549     * @param enabled The accessibility state to write to the settings.
550     * @throws Exception If any error occurs.
551     */
552    private void ensureAccessibilityEnabled(Context context, boolean enabled) throws Exception {
553        boolean isEnabled = (Settings.Secure.getInt(context.getContentResolver(),
554                Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1 ? true : false);
555
556        if (isEnabled == enabled) {
557            return;
558        }
559
560        Settings.Secure.putInt(context.getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED,
561                enabled ? 1 : 0);
562
563        // wait the accessibility manager service to pick the change up
564        Thread.sleep(TIMEOUT_BINDER_CALL);
565    }
566
567    /**
568     * Ensures the only {@link MockAccessibilityService}s with given component
569     * names are enabled by writing to the system settings and waiting until the
570     * accessibility manager service picks that up or the
571     * {@link #TIMEOUT_START_MOCK_ACCESSIBILITY_SERVICES} is exceeded.
572     *
573     * @param context A context handle to access the settings.
574     * @param firstMockServiceEnabled If the first mock accessibility service is enabled.
575     * @param secondMockServiceEnabled If the second mock accessibility service is enabled.
576     * @throws IllegalStateException If some of the requested for enabling mock services
577     *         is not properly started.
578     * @throws Exception Exception If any error occurs.
579     */
580    private void ensureOnlyMockServicesEnabled(Context context, boolean firstMockServiceEnabled,
581            boolean secondMockServiceEnabled) throws Exception {
582        String enabledServices = Settings.Secure.getString(context.getContentResolver(),
583                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
584
585        StringBuilder servicesToEnable = new StringBuilder();
586        if (firstMockServiceEnabled) {
587            servicesToEnable.append(MyFirstMockAccessibilityService.sComponentName).append(":");
588        }
589        if (secondMockServiceEnabled) {
590            servicesToEnable.append(MySecondMockAccessibilityService.sComponentName).append(":");
591        }
592
593        if (servicesToEnable.equals(enabledServices)) {
594            return;
595        }
596
597        Settings.Secure.putString(context.getContentResolver(),
598                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, servicesToEnable.toString());
599
600        // we have enabled the services of interest and need to wait until they
601        // are instantiated and started (if needed) and the system binds to them
602        boolean firstMockServiceOK = false;
603        boolean secondMockServiceOK = false;
604        long start = SystemClock.uptimeMillis();
605        long pollingInterval = TIMEOUT_START_MOCK_ACCESSIBILITY_SERVICES / 6;
606
607        while (SystemClock.uptimeMillis() - start < TIMEOUT_START_MOCK_ACCESSIBILITY_SERVICES)  {
608            firstMockServiceOK = !firstMockServiceEnabled
609                    || (MyFirstMockAccessibilityService.sInstance != null
610                    && MyFirstMockAccessibilityService.sInstance.isSystemBoundAsClient());
611
612            secondMockServiceOK = !secondMockServiceEnabled
613                    || (MySecondMockAccessibilityService.sInstance != null
614                    && MySecondMockAccessibilityService.sInstance.isSystemBoundAsClient());
615
616            if (firstMockServiceOK && secondMockServiceOK) {
617                return;
618            }
619
620            Thread.sleep(pollingInterval);
621        }
622
623        StringBuilder message = new StringBuilder();
624        message.append("Mock accessibility services not started or system not bound as a client: ");
625        if (!firstMockServiceOK) {
626            message.append(MyFirstMockAccessibilityService.sComponentName);
627            message.append(" ");
628        }
629        if (!secondMockServiceOK) {
630            message.append(MySecondMockAccessibilityService.sComponentName);
631        }
632        throw new IllegalStateException(message.toString());
633    }
634
635    /**
636     * Asserts the the mock accessibility service has been successfully verified
637     * (which is it has received the expected method calls with expected
638     * arguments) within the {@link #TIMEOUT_BINDER_CALL}. The verified state is
639     * checked by polling upon small intervals.
640     *
641     * @param service The service to verify.
642     * @throws Exception If the verification has failed with exception after the
643     *             {@link #TIMEOUT_BINDER_CALL}.
644     */
645    private void assertMockServiceVerifiedWithinTimeout(MockAccessibilityService service)
646            throws Exception {
647        Exception lastVerifyException = null;
648        long beginTime = SystemClock.uptimeMillis();
649        long pollTmeout = TIMEOUT_BINDER_CALL / 5;
650
651        // poll until the timeout has elapsed
652        while (SystemClock.uptimeMillis() - beginTime < TIMEOUT_BINDER_CALL) {
653            // sleep first since immediate call will always fail
654            try {
655                Thread.sleep(pollTmeout);
656            } catch (InterruptedException ie) {
657                /* ignore */
658            }
659            // poll for verification and if this fails save the exception and
660            // keep polling
661            try {
662                service.verify();
663                // reset so it does not accept more events
664                service.reset();
665                return;
666            } catch (Exception e) {
667                lastVerifyException = e;
668            }
669        }
670
671        // reset, we have already failed
672        service.reset();
673
674        // always not null
675        throw lastVerifyException;
676    }
677
678    /**
679     * This class is the first mock {@link AccessibilityService}.
680     */
681    public static class MyFirstMockAccessibilityService extends MockAccessibilityService {
682
683        /**
684         * The service {@link ComponentName} flattened as a string.
685         */
686        static final String sComponentName = new ComponentName(
687                sPackageName,
688                MyFirstMockAccessibilityService.class.getName()
689                ).flattenToShortString();
690
691        /**
692         * Handle to the service instance.
693         */
694        static MyFirstMockAccessibilityService sInstance;
695
696        /**
697         * Creates a new instance.
698         */
699        public MyFirstMockAccessibilityService() {
700            sInstance = this;
701        }
702    }
703
704    /**
705     * This class is the first mock {@link AccessibilityService}.
706     */
707    public static class MySecondMockAccessibilityService extends MockAccessibilityService {
708
709        /**
710         * The service {@link ComponentName} flattened as a string.
711         */
712        static final String sComponentName = new ComponentName(
713                sPackageName,
714                MySecondMockAccessibilityService.class.getName()
715                ).flattenToShortString();
716
717        /**
718         * Handle to the service instance.
719         */
720        static MySecondMockAccessibilityService sInstance;
721
722        /**
723         * Creates a new instance.
724         */
725        public MySecondMockAccessibilityService() {
726            sInstance = this;
727        }
728    }
729}
730