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 
17 package com.android.server;
18 
19 import static org.easymock.EasyMock.createStrictMock;
20 import static org.easymock.EasyMock.expect;
21 import static org.easymock.EasyMock.replay;
22 import static org.easymock.EasyMock.reportMatcher;
23 import static org.easymock.EasyMock.reset;
24 import static org.easymock.EasyMock.verify;
25 
26 import org.easymock.IArgumentMatcher;
27 
28 import android.accessibilityservice.AccessibilityServiceInfo;
29 import android.os.UserHandle;
30 import android.test.AndroidTestCase;
31 import android.test.suitebuilder.annotation.LargeTest;
32 import android.test.suitebuilder.annotation.MediumTest;
33 import android.view.accessibility.AccessibilityEvent;
34 import android.view.accessibility.AccessibilityManager;
35 import android.view.accessibility.IAccessibilityManager;
36 import android.view.accessibility.IAccessibilityManagerClient;
37 
38 import java.util.ArrayList;
39 import java.util.List;
40 
41 /**
42  * Tests for the AccessibilityManager which mocking the backing service.
43  */
44 public class AccessibilityManagerTest extends AndroidTestCase {
45 
46     /**
47      * Timeout required for pending Binder calls or event processing to
48      * complete.
49      */
50     public static final long TIMEOUT_BINDER_CALL = 50;
51 
52     /**
53      * The reusable mock {@link IAccessibilityManager}.
54      */
55     private final IAccessibilityManager mMockServiceInterface =
56         createStrictMock(IAccessibilityManager.class);
57 
58     @Override
setUp()59     public void setUp() throws Exception {
60         reset(mMockServiceInterface);
61     }
62 
63     @MediumTest
testGetAccessibilityServiceList()64     public void testGetAccessibilityServiceList() throws Exception {
65         // create a list of installed accessibility services the mock service returns
66         List<AccessibilityServiceInfo> expectedServices = new ArrayList<AccessibilityServiceInfo>();
67         AccessibilityServiceInfo accessibilityServiceInfo = new AccessibilityServiceInfo();
68         accessibilityServiceInfo.packageNames = new String[] { "foo.bar" };
69         expectedServices.add(accessibilityServiceInfo);
70 
71         // configure the mock service behavior
72         IAccessibilityManager mockServiceInterface = mMockServiceInterface;
73         expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient(),
74                 UserHandle.USER_OWNER)).andReturn(
75                 AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED);
76         expect(mockServiceInterface.getInstalledAccessibilityServiceList(UserHandle.USER_OWNER))
77                 .andReturn(expectedServices);
78         replay(mockServiceInterface);
79 
80         // invoke the method under test
81         AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface,
82                 UserHandle.USER_OWNER);
83         List<AccessibilityServiceInfo> receivedServices =
84             manager.getInstalledAccessibilityServiceList();
85 
86         // check expected result (list equals() compares it contents as well)
87         assertEquals("All expected services must be returned", receivedServices, expectedServices);
88 
89         // verify the mock service was properly called
90         verify(mockServiceInterface);
91     }
92 
93     @MediumTest
testInterrupt()94     public void testInterrupt() throws Exception {
95         // configure the mock service behavior
96         IAccessibilityManager mockServiceInterface = mMockServiceInterface;
97         expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient(),
98                 UserHandle.USER_OWNER)).andReturn(
99                         AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED);
100         mockServiceInterface.interrupt(UserHandle.USER_OWNER);
101         replay(mockServiceInterface);
102 
103         // invoke the method under test
104         AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface,
105                 UserHandle.USER_OWNER);
106         manager.interrupt();
107 
108         // verify the mock service was properly called
109         verify(mockServiceInterface);
110     }
111 
112     @LargeTest
testIsEnabled()113     public void testIsEnabled() throws Exception {
114         // configure the mock service behavior
115         IAccessibilityManager mockServiceInterface = mMockServiceInterface;
116         expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient(),
117                 UserHandle.USER_OWNER)).andReturn(
118                         AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED);
119         replay(mockServiceInterface);
120 
121         // invoke the method under test
122         AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface,
123                 UserHandle.USER_OWNER);
124         boolean isEnabledServiceEnabled = manager.isEnabled();
125 
126         // check expected result
127         assertTrue("Must be enabled since the mock service is enabled", isEnabledServiceEnabled);
128 
129         // disable accessibility
130         manager.getClient().setState(0);
131 
132         // wait for the asynchronous IBinder call to complete
133         Thread.sleep(TIMEOUT_BINDER_CALL);
134 
135         // invoke the method under test
136         boolean isEnabledServcieDisabled = manager.isEnabled();
137 
138         // check expected result
139         assertFalse("Must be disabled since the mock service is disabled",
140                 isEnabledServcieDisabled);
141 
142         // verify the mock service was properly called
143         verify(mockServiceInterface);
144     }
145 
146     @MediumTest
testSendAccessibilityEvent_AccessibilityEnabled()147     public void testSendAccessibilityEvent_AccessibilityEnabled() throws Exception {
148         // create an event to be dispatched
149         AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
150 
151         // configure the mock service behavior
152         IAccessibilityManager mockServiceInterface = mMockServiceInterface;
153         expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient(),
154                 UserHandle.USER_OWNER)).andReturn(
155                         AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED);
156         expect(mockServiceInterface.sendAccessibilityEvent(eqAccessibilityEvent(sentEvent),
157                 UserHandle.USER_OWNER)).andReturn(true);
158         expect(mockServiceInterface.sendAccessibilityEvent(eqAccessibilityEvent(sentEvent),
159                 UserHandle.USER_OWNER)).andReturn(false);
160         replay(mockServiceInterface);
161 
162         // invoke the method under test (manager and service in different processes)
163         AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface,
164                 UserHandle.USER_OWNER);
165         manager.sendAccessibilityEvent(sentEvent);
166 
167         // check expected result
168         AccessibilityEvent nextEventDifferentProcesses = AccessibilityEvent.obtain();
169         assertSame("The manager and the service are in different processes, so the event must be " +
170                 "recycled", sentEvent, nextEventDifferentProcesses);
171 
172         // invoke the method under test (manager and service in the same process)
173         manager.sendAccessibilityEvent(sentEvent);
174 
175         // check expected result
176         AccessibilityEvent nextEventSameProcess = AccessibilityEvent.obtain();
177         assertNotSame("The manager and the service are in the same process, so the event must not" +
178                 "be recycled", sentEvent, nextEventSameProcess);
179 
180         // verify the mock service was properly called
181         verify(mockServiceInterface);
182     }
183 
184     @MediumTest
testSendAccessibilityEvent_AccessibilityDisabled()185     public void testSendAccessibilityEvent_AccessibilityDisabled() throws Exception {
186         // create an event to be dispatched
187         AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
188 
189         // configure the mock service behavior
190         IAccessibilityManager mockServiceInterface = mMockServiceInterface;
191         expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient(),
192                 UserHandle.USER_OWNER)).andReturn(0);
193         replay(mockServiceInterface);
194 
195         // invoke the method under test (accessibility disabled)
196         AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface,
197                 UserHandle.USER_OWNER);
198         try {
199             manager.sendAccessibilityEvent(sentEvent);
200             fail("No accessibility events are sent if accessibility is disabled");
201         } catch (IllegalStateException ise) {
202             // check expected result
203             assertEquals("Accessibility off. Did you forget to check that?", ise.getMessage());
204         }
205 
206         // verify the mock service was properly called
207         verify(mockServiceInterface);
208     }
209 
210     /**
211      * Determines if an {@link AccessibilityEvent} passed as a method argument
212      * matches expectations.
213      *
214      * @param matched The event to check.
215      * @return True if expectations are matched.
216      */
eqAccessibilityEvent(AccessibilityEvent matched)217     private static AccessibilityEvent eqAccessibilityEvent(AccessibilityEvent matched) {
218         reportMatcher(new AccessibilityEventMather(matched));
219         return null;
220     }
221 
222     /**
223      * Determines if an {@link IAccessibilityManagerClient} passed as a method argument
224      * matches expectations which in this case are that any instance is accepted.
225      *
226      * @return <code>null</code>.
227      */
anyIAccessibilityManagerClient()228     private static IAccessibilityManagerClient anyIAccessibilityManagerClient() {
229         reportMatcher(new AnyIAccessibilityManagerClientMather());
230         return null;
231     }
232 
233     /**
234      * Matcher for {@link AccessibilityEvent}s.
235      */
236     private static class AccessibilityEventMather implements IArgumentMatcher {
237         private AccessibilityEvent mExpectedEvent;
238 
AccessibilityEventMather(AccessibilityEvent expectedEvent)239         public AccessibilityEventMather(AccessibilityEvent expectedEvent) {
240             mExpectedEvent = expectedEvent;
241         }
242 
matches(Object matched)243         public boolean matches(Object matched) {
244             if (!(matched instanceof AccessibilityEvent)) {
245                 return false;
246             }
247             AccessibilityEvent receivedEvent = (AccessibilityEvent) matched;
248             return mExpectedEvent.getEventType() == receivedEvent.getEventType();
249         }
250 
appendTo(StringBuffer buffer)251         public void appendTo(StringBuffer buffer) {
252             buffer.append("sendAccessibilityEvent()");
253             buffer.append(" with event type \"");
254             buffer.append(mExpectedEvent.getEventType());
255             buffer.append("\"");
256         }
257     }
258 
259     /**
260      * Matcher for {@link IAccessibilityManagerClient}s.
261      */
262     private static class AnyIAccessibilityManagerClientMather implements IArgumentMatcher {
matches(Object matched)263         public boolean matches(Object matched) {
264             if (!(matched instanceof IAccessibilityManagerClient)) {
265                 return false;
266             }
267             return true;
268         }
269 
appendTo(StringBuffer buffer)270         public void appendTo(StringBuffer buffer) {
271             buffer.append("addClient() with any IAccessibilityManagerClient");
272         }
273     }
274 }
275