1 /* 2 * Copyright (C) 2022 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.accessibility; 18 19 import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_AUDIBLE; 20 import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_GENERIC; 21 import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; 22 import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS; 23 import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE; 24 25 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; 26 27 import android.accessibilityservice.AccessibilityServiceInfo; 28 import android.accessibilityservice.AccessibilityTrace; 29 import android.content.ComponentName; 30 import android.content.Context; 31 import android.content.res.Resources; 32 import android.graphics.Color; 33 import android.os.Handler; 34 import android.view.accessibility.AccessibilityEvent; 35 36 import static com.google.common.truth.Truth.assertThat; 37 38 import static org.junit.Assert.assertThrows; 39 import static org.mockito.ArgumentMatchers.any; 40 import static org.mockito.Mockito.verify; 41 import static org.mockito.Mockito.when; 42 43 import com.android.server.wm.WindowManagerInternal; 44 45 import org.junit.Before; 46 import org.junit.Test; 47 import org.mockito.Mock; 48 import org.mockito.MockitoAnnotations; 49 50 import java.util.ArrayList; 51 import java.util.List; 52 53 public class ProxyAccessibilityServiceConnectionTest { 54 private static final int DISPLAY_ID = 1000; 55 private static final int DEVICE_ID = 2000; 56 private static final int CONNECTION_ID = 1000; 57 private static final ComponentName COMPONENT_NAME = new ComponentName( 58 "com.android.server.accessibility", ".ProxyAccessibilityServiceConnectionTest"); 59 public static final int NON_INTERACTIVE_UI_TIMEOUT_100MS = 100; 60 public static final int NON_INTERACTIVE_UI_TIMEOUT_200MS = 200; 61 public static final int INTERACTIVE_UI_TIMEOUT_100MS = 100; 62 public static final int INTERACTIVE_UI_TIMEOUT_200MS = 200; 63 public static final int NOTIFICATION_TIMEOUT_100MS = 100; 64 public static final int NOTIFICATION_TIMEOUT_200MS = 200; 65 public static final String PACKAGE_1 = "package 1"; 66 public static final String PACKAGE_2 = "package 2"; 67 public static final String PACKAGE_3 = "package 3"; 68 69 @Mock 70 Context mMockContext; 71 @Mock 72 Object mMockLock; 73 @Mock 74 AccessibilitySecurityPolicy mMockSecurityPolicy; 75 @Mock 76 AccessibilityWindowManager mMockA11yWindowManager; 77 @Mock AbstractAccessibilityServiceConnection.SystemSupport mMockSystemSupport; 78 @Mock 79 AccessibilityTrace mMockA11yTrace; 80 @Mock 81 WindowManagerInternal mMockWindowManagerInternal; 82 ProxyAccessibilityServiceConnection mProxyConnection; 83 AccessibilityServiceInfo mAccessibilityServiceInfo; 84 private int mFocusStrokeWidthDefaultValue; 85 private int mFocusColorDefaultValue; 86 87 @Before setup()88 public void setup() { 89 final Resources resources = getInstrumentation().getContext().getResources(); 90 MockitoAnnotations.initMocks(this); 91 when(mMockContext.getResources()).thenReturn(resources); 92 when(mMockSecurityPolicy.checkAccessibilityAccess(any())).thenReturn(true); 93 94 mAccessibilityServiceInfo = new AccessibilityServiceInfo(); 95 mProxyConnection = new ProxyAccessibilityServiceConnection(mMockContext, COMPONENT_NAME, 96 mAccessibilityServiceInfo, CONNECTION_ID , new Handler( 97 getInstrumentation().getContext().getMainLooper()), 98 mMockLock, mMockSecurityPolicy, mMockSystemSupport, mMockA11yTrace, 99 mMockWindowManagerInternal, mMockA11yWindowManager, DISPLAY_ID, DEVICE_ID); 100 101 mFocusStrokeWidthDefaultValue = mProxyConnection.getFocusStrokeWidthLocked(); 102 mFocusColorDefaultValue = mProxyConnection.getFocusColorLocked(); 103 } 104 105 @Test testSetInstalledAndEnabledServices_updateInfos_notifiesSystemOfProxyChange()106 public void testSetInstalledAndEnabledServices_updateInfos_notifiesSystemOfProxyChange() { 107 final List<AccessibilityServiceInfo> infos = new ArrayList<>(); 108 final AccessibilityServiceInfo info1 = new AccessibilityServiceInfo(); 109 infos.add(info1); 110 111 mProxyConnection.setInstalledAndEnabledServices(infos); 112 113 verify(mMockSystemSupport).onProxyChanged(DEVICE_ID); 114 } 115 116 @Test testSetFocusAppearance_updateAppearance_notifiesSystemOfProxyChange()117 public void testSetFocusAppearance_updateAppearance_notifiesSystemOfProxyChange() { 118 final int updatedWidth = mFocusStrokeWidthDefaultValue + 10; 119 final int updatedColor = mFocusColorDefaultValue 120 == Color.BLUE ? Color.RED : Color.BLUE; 121 122 mProxyConnection.setFocusAppearance(updatedWidth, updatedColor); 123 124 verify(mMockSystemSupport).onProxyChanged(DEVICE_ID); 125 } 126 127 @Test testSetInstalledAndEnabledServices_returnList()128 public void testSetInstalledAndEnabledServices_returnList() { 129 final List<AccessibilityServiceInfo> infos = new ArrayList<>(); 130 final AccessibilityServiceInfo info1 = new AccessibilityServiceInfo(); 131 final AccessibilityServiceInfo info2 = new AccessibilityServiceInfo(); 132 infos.add(info1); 133 infos.add(info2); 134 135 mProxyConnection.setInstalledAndEnabledServices(infos); 136 final List<AccessibilityServiceInfo> infoList = 137 mProxyConnection.getInstalledAndEnabledServices(); 138 139 assertThat(infoList.size()).isEqualTo(2); 140 assertThat(infoList.get(0)).isEqualTo(info1); 141 assertThat(infoList.get(1)).isEqualTo(info2); 142 } 143 144 @Test testSetInstalledAndEnabledServices_defaultNamesPopulated()145 public void testSetInstalledAndEnabledServices_defaultNamesPopulated() { 146 final List<AccessibilityServiceInfo> infos = new ArrayList<>(); 147 final AccessibilityServiceInfo info1 = new AccessibilityServiceInfo(); 148 infos.add(info1); 149 150 mProxyConnection.setInstalledAndEnabledServices(infos); 151 final List<AccessibilityServiceInfo> infoList = 152 mProxyConnection.getInstalledAndEnabledServices(); 153 154 assertThat(infoList.get(0).getComponentName()).isNotNull(); 155 assertThat(infoList.get(0).getResolveInfo()).isNotNull(); 156 } 157 158 @Test testSetInstalledAndEnabledServices_connectionInfoIsUnion()159 public void testSetInstalledAndEnabledServices_connectionInfoIsUnion() { 160 final List<AccessibilityServiceInfo> infos = new ArrayList<>(); 161 final AccessibilityServiceInfo info1 = new AccessibilityServiceInfo(); 162 info1.setAccessibilityTool(true); 163 info1.packageNames = new String[]{PACKAGE_1, PACKAGE_2}; 164 info1.setInteractiveUiTimeoutMillis(INTERACTIVE_UI_TIMEOUT_200MS); 165 info1.setNonInteractiveUiTimeoutMillis(NON_INTERACTIVE_UI_TIMEOUT_100MS); 166 info1.notificationTimeout = NOTIFICATION_TIMEOUT_100MS; 167 info1.eventTypes = AccessibilityEvent.TYPE_VIEW_CLICKED; 168 info1.feedbackType = FEEDBACK_AUDIBLE; 169 info1.flags = FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; 170 infos.add(info1); 171 172 final AccessibilityServiceInfo info2 = new AccessibilityServiceInfo(); 173 info2.packageNames = new String[]{PACKAGE_2, PACKAGE_3}; 174 info2.setInteractiveUiTimeoutMillis(INTERACTIVE_UI_TIMEOUT_100MS); 175 info2.setNonInteractiveUiTimeoutMillis(NON_INTERACTIVE_UI_TIMEOUT_200MS); 176 info2.notificationTimeout = NOTIFICATION_TIMEOUT_200MS; 177 info2.eventTypes = AccessibilityEvent.TYPES_ALL_MASK; 178 info2.feedbackType = FEEDBACK_GENERIC; 179 info2.flags = FLAG_REQUEST_TOUCH_EXPLORATION_MODE | FLAG_REPORT_VIEW_IDS; 180 infos.add(info2); 181 182 mProxyConnection.setInstalledAndEnabledServices(infos); 183 184 assertThat(mAccessibilityServiceInfo.isAccessibilityTool()).isTrue(); 185 // Package 1, 2, 3 186 assertThat(mAccessibilityServiceInfo.packageNames).asList().containsExactly( 187 PACKAGE_1, PACKAGE_2, PACKAGE_3); 188 assertThat(mAccessibilityServiceInfo.getInteractiveUiTimeoutMillis()).isEqualTo( 189 INTERACTIVE_UI_TIMEOUT_200MS); 190 assertThat(mAccessibilityServiceInfo.getNonInteractiveUiTimeoutMillis()).isEqualTo( 191 NON_INTERACTIVE_UI_TIMEOUT_200MS); 192 assertThat(mAccessibilityServiceInfo.notificationTimeout).isEqualTo( 193 NOTIFICATION_TIMEOUT_200MS); 194 assertThat(mAccessibilityServiceInfo.eventTypes).isEqualTo( 195 AccessibilityEvent.TYPES_ALL_MASK); 196 assertThat(mAccessibilityServiceInfo.feedbackType).isEqualTo(FEEDBACK_AUDIBLE 197 | FEEDBACK_GENERIC); 198 assertThat(mAccessibilityServiceInfo.flags).isEqualTo(FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 199 | FLAG_REQUEST_TOUCH_EXPLORATION_MODE | FLAG_REPORT_VIEW_IDS); 200 } 201 202 @Test testSetInstalledAndEnabledServices_emptyPackageNames_packageNamesIsNull()203 public void testSetInstalledAndEnabledServices_emptyPackageNames_packageNamesIsNull() { 204 final List<AccessibilityServiceInfo> infos = new ArrayList<>(); 205 final AccessibilityServiceInfo info1 = new AccessibilityServiceInfo(); 206 info1.packageNames = new String[]{PACKAGE_1, PACKAGE_2}; 207 infos.add(info1); 208 final AccessibilityServiceInfo info2 = new AccessibilityServiceInfo(); 209 infos.add(info2); 210 211 mProxyConnection.setInstalledAndEnabledServices(infos); 212 213 final String[] packageNames = mAccessibilityServiceInfo.packageNames; 214 assertThat(packageNames).isNull(); 215 } 216 217 @Test testSetServiceInfo_setIllegalOperationExceptionThrown()218 public void testSetServiceInfo_setIllegalOperationExceptionThrown() { 219 UnsupportedOperationException thrown = 220 assertThrows( 221 UnsupportedOperationException.class, 222 () -> mProxyConnection.setServiceInfo(new AccessibilityServiceInfo())); 223 224 assertThat(thrown).hasMessageThat().contains("setServiceInfo is not supported"); 225 } 226 227 @Test testDisableSelf_setIllegalOperationExceptionThrown_()228 public void testDisableSelf_setIllegalOperationExceptionThrown_() { 229 UnsupportedOperationException thrown = 230 assertThrows( 231 UnsupportedOperationException.class, 232 () -> mProxyConnection.disableSelf()); 233 234 assertThat(thrown).hasMessageThat().contains("disableSelf is not supported"); 235 } 236 } 237