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