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.accessibility;
18
19import static junit.framework.TestCase.assertFalse;
20import static junit.framework.TestCase.assertSame;
21import static org.junit.Assert.assertEquals;
22import static org.junit.Assert.assertTrue;
23import static org.junit.Assert.fail;
24import static org.mockito.Matchers.any;
25import static org.mockito.Matchers.anyInt;
26import static org.mockito.Mockito.verify;
27import static org.mockito.Mockito.when;
28
29import android.accessibilityservice.AccessibilityServiceInfo;
30import android.app.Instrumentation;
31import android.os.Looper;
32import android.os.UserHandle;
33import android.support.test.InstrumentationRegistry;
34import android.support.test.runner.AndroidJUnit4;
35import android.view.accessibility.AccessibilityEvent;
36import android.view.accessibility.AccessibilityManager;
37import android.view.accessibility.IAccessibilityManager;
38import android.view.accessibility.IAccessibilityManagerClient;
39
40import com.android.internal.util.IntPair;
41
42import org.junit.Before;
43import org.junit.BeforeClass;
44import org.junit.Test;
45import org.junit.runner.RunWith;
46import org.mockito.Mock;
47import org.mockito.MockitoAnnotations;
48
49import java.util.ArrayList;
50import java.util.List;
51
52/**
53 * Tests for the AccessibilityManager by mocking the backing service.
54 */
55@RunWith(AndroidJUnit4.class)
56public class AccessibilityManagerTest {
57    private static final boolean WITH_A11Y_ENABLED = true;
58    private static final boolean WITH_A11Y_DISABLED = false;
59
60    @Mock private IAccessibilityManager mMockService;
61    private MessageCapturingHandler mHandler;
62    private Instrumentation mInstrumentation;
63
64    @BeforeClass
65    public static void oneTimeInitialization() {
66        if (Looper.myLooper() == null) {
67            Looper.prepare();
68        }
69    }
70
71    @Before
72    public void setUp() throws Exception {
73        MockitoAnnotations.initMocks(this);
74        mHandler = new MessageCapturingHandler(null);
75        mInstrumentation = InstrumentationRegistry.getInstrumentation();
76    }
77
78    private AccessibilityManager createManager(boolean enabled) throws Exception {
79        long serviceReturnValue = IntPair.of(
80                (enabled) ? AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED : 0,
81                AccessibilityEvent.TYPES_ALL_MASK);
82        when(mMockService.addClient(any(IAccessibilityManagerClient.class), anyInt()))
83                .thenReturn(serviceReturnValue);
84
85        AccessibilityManager manager =
86                new AccessibilityManager(mHandler, mMockService, UserHandle.USER_CURRENT);
87
88        verify(mMockService).addClient(any(IAccessibilityManagerClient.class), anyInt());
89        mHandler.setCallback(manager.getCallback());
90        mHandler.sendAllMessages();
91        return manager;
92    }
93
94    @Test
95    public void testGetAccessibilityServiceList() throws Exception {
96        // create a list of installed accessibility services the mock service returns
97        List<AccessibilityServiceInfo> expectedServices = new ArrayList<>();
98        AccessibilityServiceInfo accessibilityServiceInfo = new AccessibilityServiceInfo();
99        accessibilityServiceInfo.packageNames = new String[] { "foo.bar" };
100        expectedServices.add(accessibilityServiceInfo);
101
102        // configure the mock service behavior
103        when(mMockService.getInstalledAccessibilityServiceList(anyInt()))
104                .thenReturn(expectedServices);
105
106        // invoke the method under test
107        AccessibilityManager manager = createManager(true);
108        List<AccessibilityServiceInfo> receivedServices =
109                manager.getInstalledAccessibilityServiceList();
110
111        verify(mMockService).getInstalledAccessibilityServiceList(UserHandle.USER_CURRENT);
112        // check expected result (list equals() compares it contents as well)
113        assertEquals("All expected services must be returned", expectedServices, receivedServices);
114    }
115
116    @Test
117    public void testInterrupt() throws Exception {
118        AccessibilityManager manager = createManager(WITH_A11Y_ENABLED);
119        manager.interrupt();
120
121        verify(mMockService).interrupt(UserHandle.USER_CURRENT);
122    }
123
124    @Test
125    public void testIsEnabled() throws Exception {
126        // Create manager with a11y enabled
127        AccessibilityManager manager = createManager(WITH_A11Y_ENABLED);
128        assertTrue("Must be enabled since the mock service is enabled", manager.isEnabled());
129
130        // Disable accessibility
131        manager.getClient().setState(0);
132        mHandler.sendAllMessages();
133        assertFalse("Must be disabled since the mock service is disabled", manager.isEnabled());
134    }
135
136    @Test
137    public void testSendAccessibilityEvent_AccessibilityEnabled() throws Exception {
138        AccessibilityEvent sentEvent = AccessibilityEvent.obtain(
139                AccessibilityEvent.TYPE_ANNOUNCEMENT);
140
141        AccessibilityManager manager = createManager(WITH_A11Y_ENABLED);
142        manager.sendAccessibilityEvent(sentEvent);
143
144        assertSame("The event should be recycled.", sentEvent, AccessibilityEvent.obtain());
145    }
146
147    @Test
148    public void testSendAccessibilityEvent_AccessibilityDisabled() throws Exception {
149        AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
150
151        AccessibilityManager manager = createManager(WITH_A11Y_DISABLED);
152        mInstrumentation.runOnMainSync(() -> {
153            try {
154                manager.sendAccessibilityEvent(sentEvent);
155                fail("No accessibility events are sent if accessibility is disabled");
156            } catch (IllegalStateException ise) {
157                // check expected result
158                assertEquals("Accessibility off. Did you forget to check that?", ise.getMessage());
159            }
160        });
161    }
162}
163