MockAccessibilityService.java revision 0b29a587142b19ed25dd6489cfa037d06145afd1
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.os.Message;
22import android.view.accessibility.AccessibilityEvent;
23
24import java.util.Iterator;
25import java.util.LinkedList;
26import java.util.List;
27import java.util.Queue;
28
29import junit.framework.TestCase;
30
31/**
32 * This is the base class for mock {@link AccessibilityService}s.
33 */
34public abstract class MockAccessibilityService extends AccessibilityService {
35
36    /**
37     * The event this service expects to receive.
38     */
39    private final Queue<AccessibilityEvent> mExpectedEvents = new LinkedList<AccessibilityEvent>();
40
41    /**
42     * Interruption call this service expects to receive.
43     */
44    private boolean mExpectedInterrupt;
45
46    /**
47     * Flag if the mock is currently replaying.
48     */
49    private boolean mReplaying;
50
51    /**
52     * Creates an {@link AccessibilityServiceInfo} populated with default
53     * values.
54     *
55     * @return The default info.
56     */
57    public static AccessibilityServiceInfo createDefaultInfo() {
58        AccessibilityServiceInfo defaultInfo = new AccessibilityServiceInfo();
59        defaultInfo.eventTypes = AccessibilityEvent.TYPE_VIEW_CLICKED;
60        defaultInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_AUDIBLE;
61        defaultInfo.flags = 0;
62        defaultInfo.notificationTimeout = 0;
63        defaultInfo.packageNames = new String[] {
64            "foo.bar.baz"
65        };
66
67        return defaultInfo;
68    }
69
70    /**
71     * Starts replaying the mock.
72     */
73    public void replay() {
74        mReplaying = true;
75    }
76
77    /**
78     * Verifies if all expected service methods have been called.
79     */
80    public void verify() {
81        if (!mReplaying) {
82            throw new IllegalStateException("Did you forget to call replay()");
83        }
84
85        if (mExpectedInterrupt) {
86            throw new IllegalStateException("Expected call to #interrupt() not received");
87        }
88        if (!mExpectedEvents.isEmpty()) {
89            throw new IllegalStateException("Expected a call to onAccessibilityEvent() for "
90                    + "events \"" + mExpectedEvents + "\" not received");
91        }
92    }
93
94    /**
95     * Resets this instance so it can be reused.
96     */
97    public void reset() {
98        mExpectedEvents.clear();
99        mExpectedInterrupt = false;
100        mReplaying = false;
101    }
102
103    /**
104     * Sets an expected call to
105     * {@link #onAccessibilityEvent(AccessibilityEvent)} with given event as
106     * argument.
107     *
108     * @param expectedEvent The expected event argument.
109     */
110    public void expectEvent(AccessibilityEvent expectedEvent) {
111        mExpectedEvents.add(expectedEvent);
112    }
113
114    /**
115     * Sets an expected call of {@link #onInterrupt()}.
116     */
117    public void expectInterrupt() {
118        mExpectedInterrupt = true;
119    }
120
121    @Override
122    public void onAccessibilityEvent(AccessibilityEvent receivedEvent) {
123        if (!mReplaying) {
124            return;
125        }
126
127        if (mExpectedEvents.isEmpty()) {
128            throw new IllegalStateException("Unexpected event: " + receivedEvent);
129        }
130
131        AccessibilityEvent expectedEvent = mExpectedEvents.poll();
132        assertEqualsAccessiblityEvent(expectedEvent, receivedEvent);
133    }
134
135    @Override
136    public void onInterrupt() {
137        if (!mReplaying) {
138            return;
139        }
140
141        if (!mExpectedInterrupt) {
142            throw new IllegalStateException("Unexpected call to onInterrupt()");
143        }
144
145        mExpectedInterrupt = false;
146    }
147
148    /**
149     * Compares all properties of the <code>expectedEvent</code> and the
150     * <code>receviedEvent</code> to verify that the received event is the one
151     * that is expected.
152     */
153    private void assertEqualsAccessiblityEvent(AccessibilityEvent expectedEvent,
154            AccessibilityEvent receivedEvent) {
155        TestCase.assertEquals("addedCount has incorrect value", expectedEvent.getAddedCount(),
156                receivedEvent.getAddedCount());
157        TestCase.assertEquals("beforeText has incorrect value", expectedEvent.getBeforeText(),
158                receivedEvent.getBeforeText());
159        TestCase.assertEquals("checked has incorrect value", expectedEvent.isChecked(),
160                receivedEvent.isChecked());
161        TestCase.assertEquals("className has incorrect value", expectedEvent.getClassName(),
162                receivedEvent.getClassName());
163        TestCase.assertEquals("contentDescription has incorrect value", expectedEvent
164                .getContentDescription(), receivedEvent.getContentDescription());
165        TestCase.assertEquals("currentItemIndex has incorrect value", expectedEvent
166                .getCurrentItemIndex(), receivedEvent.getCurrentItemIndex());
167        TestCase.assertEquals("enabled has incorrect value", expectedEvent.isEnabled(),
168                receivedEvent.isEnabled());
169        TestCase.assertEquals("eventType has incorrect value", expectedEvent.getEventType(),
170                receivedEvent.getEventType());
171        TestCase.assertEquals("fromIndex has incorrect value", expectedEvent.getFromIndex(),
172                receivedEvent.getFromIndex());
173        TestCase.assertEquals("fullScreen has incorrect value", expectedEvent.isFullScreen(),
174                receivedEvent.isFullScreen());
175        TestCase.assertEquals("itemCount has incorrect value", expectedEvent.getItemCount(),
176                receivedEvent.getItemCount());
177        assertEqualsNotificationAsParcelableData(expectedEvent, receivedEvent);
178        TestCase.assertEquals("password has incorrect value", expectedEvent.isPassword(),
179                receivedEvent.isPassword());
180        TestCase.assertEquals("removedCount has incorrect value", expectedEvent.getRemovedCount(),
181                receivedEvent.getRemovedCount());
182        assertEqualsText(expectedEvent, receivedEvent);
183    }
184
185    /**
186     * Compares the {@link android.os.Parcelable} data of the
187     * <code>expectedEvent</code> and <code>receivedEvent</code> to verify that
188     * the received event is the one that is expected.
189     */
190    private void assertEqualsNotificationAsParcelableData(AccessibilityEvent expectedEvent,
191            AccessibilityEvent receivedEvent) {
192        String message = "parcelableData has incorrect value";
193        Message expectedMessage = (Message) expectedEvent.getParcelableData();
194        Message receivedMessage = (Message) receivedEvent.getParcelableData();
195
196        if (expectedMessage == null) {
197            if (receivedMessage == null) {
198                return;
199            }
200        }
201
202        TestCase.assertNotNull(message, receivedMessage);
203
204        // we do a very simple sanity check since we do not test Message
205        TestCase.assertEquals(message, expectedMessage.what, receivedMessage.what);
206    }
207
208    /**
209     * Compares the text of the <code>expectedEvent</code> and
210     * <code>receivedEvent</code> by comparing the string representation of the
211     * corresponding {@link CharSequence}s.
212     */
213    private void assertEqualsText(AccessibilityEvent expectedEvent,
214            AccessibilityEvent receivedEvent) {
215        String message = "text has incorrect value";
216        List<CharSequence> expectedText = expectedEvent.getText();
217        List<CharSequence> receivedText = receivedEvent.getText();
218
219        TestCase.assertEquals(message, expectedText.size(), receivedText.size());
220
221        Iterator<CharSequence> expectedTextIterator = expectedText.iterator();
222        Iterator<CharSequence> receivedTextIterator = receivedText.iterator();
223
224        for (int i = 0; i < expectedText.size(); i++) {
225            // compare the string representation
226            TestCase.assertEquals(message, expectedTextIterator.next().toString(),
227                    receivedTextIterator.next().toString());
228        }
229    }
230}
231