1 /* 2 * Copyright (C) 2019 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.AccessibilityService.ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY; 20 import static android.accessibilityservice.AccessibilityService.ERROR_TAKE_SCREENSHOT_NO_ACCESSIBILITY_ACCESS; 21 import static android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_HOME; 22 import static android.accessibilityservice.AccessibilityService.KEY_ACCESSIBILITY_SCREENSHOT_STATUS; 23 import static android.accessibilityservice.AccessibilityServiceInfo.CAPABILITY_CAN_CONTROL_MAGNIFICATION; 24 import static android.accessibilityservice.AccessibilityServiceInfo.CAPABILITY_CAN_PERFORM_GESTURES; 25 import static android.accessibilityservice.AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS; 26 import static android.accessibilityservice.AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION; 27 import static android.accessibilityservice.AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT; 28 import static android.accessibilityservice.AccessibilityServiceInfo.DEFAULT; 29 import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_HAPTIC; 30 import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_SPOKEN; 31 import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; 32 import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS; 33 import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON; 34 import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS; 35 import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_REQUEST_FINGERPRINT_GESTURES; 36 import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE; 37 import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS; 38 import static android.content.pm.PackageManager.FEATURE_FINGERPRINT; 39 import static android.view.View.FOCUS_DOWN; 40 import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_CLICKED; 41 import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_LONG_CLICKED; 42 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS; 43 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK; 44 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK; 45 import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 46 import static android.view.accessibility.AccessibilityNodeInfo.FOCUS_INPUT; 47 import static android.view.accessibility.AccessibilityNodeInfo.ROOT_NODE_ID; 48 49 import static org.hamcrest.Matchers.hasItems; 50 import static org.hamcrest.Matchers.is; 51 import static org.hamcrest.Matchers.nullValue; 52 import static org.junit.Assert.assertEquals; 53 import static org.junit.Assert.assertFalse; 54 import static org.junit.Assert.assertThat; 55 import static org.junit.Assert.assertTrue; 56 import static org.mockito.ArgumentMatchers.any; 57 import static org.mockito.ArgumentMatchers.anyBoolean; 58 import static org.mockito.ArgumentMatchers.anyInt; 59 import static org.mockito.ArgumentMatchers.anyLong; 60 import static org.mockito.ArgumentMatchers.eq; 61 import static org.mockito.ArgumentMatchers.nullable; 62 import static org.mockito.Mockito.doAnswer; 63 import static org.mockito.Mockito.doReturn; 64 import static org.mockito.Mockito.mock; 65 import static org.mockito.Mockito.never; 66 import static org.mockito.Mockito.verify; 67 import static org.mockito.Mockito.verifyNoMoreInteractions; 68 import static org.mockito.Mockito.when; 69 70 import android.accessibilityservice.AccessibilityService; 71 import android.accessibilityservice.AccessibilityServiceInfo; 72 import android.accessibilityservice.AccessibilityTrace; 73 import android.accessibilityservice.IAccessibilityServiceClient; 74 import android.accessibilityservice.MagnificationConfig; 75 import android.content.ComponentName; 76 import android.content.Context; 77 import android.content.pm.ApplicationInfo; 78 import android.content.pm.PackageManager; 79 import android.content.pm.ResolveInfo; 80 import android.content.pm.ServiceInfo; 81 import android.graphics.Region; 82 import android.hardware.display.DisplayManager; 83 import android.os.Build; 84 import android.os.Handler; 85 import android.os.IBinder; 86 import android.os.IPowerManager; 87 import android.os.IThermalService; 88 import android.os.PowerManager; 89 import android.os.Process; 90 import android.os.RemoteCallback; 91 import android.os.RemoteException; 92 import android.util.Pair; 93 import android.view.Display; 94 import android.view.KeyEvent; 95 import android.view.MagnificationSpec; 96 import android.view.accessibility.AccessibilityNodeInfo; 97 import android.view.accessibility.AccessibilityWindowInfo; 98 import android.view.accessibility.IAccessibilityInteractionConnection; 99 import android.view.accessibility.IAccessibilityInteractionConnectionCallback; 100 101 import com.android.server.accessibility.AccessibilityWindowManager.RemoteAccessibilityConnection; 102 import com.android.server.accessibility.magnification.MagnificationProcessor; 103 import com.android.server.accessibility.test.MessageCapturingHandler; 104 import com.android.server.wm.WindowManagerInternal; 105 106 import org.junit.Before; 107 import org.junit.Test; 108 import org.mockito.ArgumentCaptor; 109 import org.mockito.Mock; 110 import org.mockito.Mockito; 111 import org.mockito.MockitoAnnotations; 112 import org.mockito.Spy; 113 114 import java.util.ArrayList; 115 import java.util.Arrays; 116 import java.util.List; 117 import java.util.concurrent.Callable; 118 119 /** 120 * Tests for the AbstractAccessibilityServiceConnection 121 */ 122 public class AbstractAccessibilityServiceConnectionTest { 123 private static final ComponentName COMPONENT_NAME = new ComponentName( 124 "com.android.server.accessibility", ".AbstractAccessibilityServiceConnectionTest"); 125 private static final String PACKAGE_NAME1 = "com.android.server.accessibility1"; 126 private static final String PACKAGE_NAME2 = "com.android.server.accessibility2"; 127 private static final String VIEWID_RESOURCE_NAME = "test_viewid_resource_name"; 128 private static final String VIEW_TEXT = "test_view_text"; 129 private static final int WINDOWID = 12; 130 private static final int PIP_WINDOWID = 13; 131 private static final int WINDOWID_ONSECONDDISPLAY = 14; 132 private static final int SECONDARY_DISPLAY_ID = Display.DEFAULT_DISPLAY + 1; 133 private static final int SERVICE_ID = 42; 134 private static final int A11Y_SERVICE_CAPABILITY = CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT 135 | CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION 136 | CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS 137 | CAPABILITY_CAN_CONTROL_MAGNIFICATION 138 | CAPABILITY_CAN_PERFORM_GESTURES; 139 private static final int A11Y_SERVICE_FLAG = DEFAULT 140 | FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 141 | FLAG_REPORT_VIEW_IDS 142 | FLAG_REQUEST_TOUCH_EXPLORATION_MODE 143 | FLAG_REQUEST_FILTER_KEY_EVENTS 144 | FLAG_REQUEST_FINGERPRINT_GESTURES 145 | FLAG_REQUEST_ACCESSIBILITY_BUTTON 146 | FLAG_RETRIEVE_INTERACTIVE_WINDOWS; 147 private static final int USER_ID = 1; 148 private static final int USER_ID2 = 2; 149 private static final int INTERACTION_ID = 199; 150 private static final Pair<float[], MagnificationSpec> FAKE_MATRIX_AND_MAG_SPEC = 151 new Pair<>(new float[9], new MagnificationSpec()); 152 private static final int PID = Process.myPid(); 153 private static final long TID = Process.myTid(); 154 private static final int UID = Process.myUid(); 155 156 private AbstractAccessibilityServiceConnection mServiceConnection; 157 private MessageCapturingHandler mHandler = new MessageCapturingHandler(null); 158 private final List<AccessibilityWindowInfo> mA11yWindowInfos = new ArrayList<>(); 159 private final List<AccessibilityWindowInfo> mA11yWindowInfosOnSecondDisplay = new ArrayList<>(); 160 private Callable[] mFindA11yNodesFunctions; 161 private Callable<Boolean> mPerformA11yAction; 162 private ArrayList<Integer> mDisplayList = new ArrayList<>(Arrays.asList( 163 Display.DEFAULT_DISPLAY, SECONDARY_DISPLAY_ID)); 164 165 @Mock private Context mMockContext; 166 @Mock private IPowerManager mMockIPowerManager; 167 @Mock private IThermalService mMockIThermalService; 168 @Mock private PackageManager mMockPackageManager; 169 @Spy private AccessibilityServiceInfo mSpyServiceInfo = new AccessibilityServiceInfo(); 170 @Mock private AccessibilitySecurityPolicy mMockSecurityPolicy; 171 @Mock private AccessibilityWindowManager mMockA11yWindowManager; 172 @Mock private AbstractAccessibilityServiceConnection.SystemSupport mMockSystemSupport; 173 @Mock private AccessibilityTrace mMockA11yTrace; 174 @Mock private WindowManagerInternal mMockWindowManagerInternal; 175 @Mock private SystemActionPerformer mMockSystemActionPerformer; 176 @Mock private IBinder mMockService; 177 @Mock private IAccessibilityServiceClient mMockServiceInterface; 178 @Mock private KeyEventDispatcher mMockKeyEventDispatcher; 179 @Mock private IAccessibilityInteractionConnection mMockIA11yInteractionConnection; 180 @Mock private IAccessibilityInteractionConnectionCallback mMockCallback; 181 @Mock private FingerprintGestureDispatcher mMockFingerprintGestureDispatcher; 182 @Mock private MagnificationProcessor mMockMagnificationProcessor; 183 @Mock private RemoteCallback.OnResultListener mMockListener; 184 185 @Before setup()186 public void setup() { 187 MockitoAnnotations.initMocks(this); 188 189 when(mMockSystemSupport.getCurrentUserIdLocked()).thenReturn(USER_ID); 190 when(mMockSystemSupport.getKeyEventDispatcher()).thenReturn(mMockKeyEventDispatcher); 191 when(mMockSystemSupport.getFingerprintGestureDispatcher()) 192 .thenReturn(mMockFingerprintGestureDispatcher); 193 when(mMockSystemSupport.getMagnificationProcessor()) 194 .thenReturn(mMockMagnificationProcessor); 195 when(mMockSystemSupport.getWindowTransformationMatrixAndMagnificationSpec(anyInt())) 196 .thenReturn(FAKE_MATRIX_AND_MAG_SPEC); 197 198 PowerManager powerManager = 199 new PowerManager(mMockContext, mMockIPowerManager, mMockIThermalService, mHandler); 200 when(mMockContext.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager); 201 when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager); 202 when(mMockPackageManager.hasSystemFeature(FEATURE_FINGERPRINT)).thenReturn(true); 203 204 when(mMockA11yTrace.isA11yTracingEnabled()).thenReturn(false); 205 // Fake a11yWindowInfo and remote a11y connection for tests. 206 addA11yWindowInfo(mA11yWindowInfos, WINDOWID, false, Display.DEFAULT_DISPLAY); 207 addA11yWindowInfo(mA11yWindowInfos, PIP_WINDOWID, true, Display.DEFAULT_DISPLAY); 208 addA11yWindowInfo(mA11yWindowInfosOnSecondDisplay, WINDOWID_ONSECONDDISPLAY, false, 209 SECONDARY_DISPLAY_ID); 210 when(mMockA11yWindowManager.getDisplayListLocked(anyInt())).thenReturn(mDisplayList); 211 when(mMockA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY)) 212 .thenReturn(mA11yWindowInfos); 213 when(mMockA11yWindowManager.findA11yWindowInfoByIdLocked(WINDOWID)) 214 .thenReturn(mA11yWindowInfos.get(0)); 215 when(mMockA11yWindowManager.findA11yWindowInfoByIdLocked(PIP_WINDOWID)) 216 .thenReturn(mA11yWindowInfos.get(1)); 217 when(mMockA11yWindowManager.getDisplayIdByUserIdAndWindowIdLocked(USER_ID, 218 WINDOWID_ONSECONDDISPLAY)).thenReturn(SECONDARY_DISPLAY_ID); 219 when(mMockA11yWindowManager.getWindowListLocked(SECONDARY_DISPLAY_ID)) 220 .thenReturn(mA11yWindowInfosOnSecondDisplay); 221 when(mMockA11yWindowManager.findA11yWindowInfoByIdLocked(WINDOWID_ONSECONDDISPLAY)) 222 .thenReturn(mA11yWindowInfosOnSecondDisplay.get(0)); 223 final RemoteAccessibilityConnection conn = getRemoteA11yConnection( 224 WINDOWID, mMockIA11yInteractionConnection, PACKAGE_NAME1); 225 final RemoteAccessibilityConnection connPip = getRemoteA11yConnection( 226 PIP_WINDOWID, mMockIA11yInteractionConnection, PACKAGE_NAME2); 227 when(mMockA11yWindowManager.getConnectionLocked(USER_ID, WINDOWID)).thenReturn(conn); 228 when(mMockA11yWindowManager.getConnectionLocked(USER_ID, PIP_WINDOWID)).thenReturn(connPip); 229 when(mMockA11yWindowManager.getPictureInPictureActionReplacingConnection()) 230 .thenReturn(connPip); 231 232 // Update a11yServiceInfo to full capability, full flags and target sdk jelly bean 233 final ResolveInfo mockResolveInfo = mock(ResolveInfo.class); 234 mockResolveInfo.serviceInfo = mock(ServiceInfo.class); 235 mockResolveInfo.serviceInfo.applicationInfo = mock(ApplicationInfo.class); 236 mockResolveInfo.serviceInfo.applicationInfo.targetSdkVersion = 237 Build.VERSION_CODES.JELLY_BEAN; 238 doReturn(mockResolveInfo).when(mSpyServiceInfo).getResolveInfo(); 239 mSpyServiceInfo.setCapabilities(A11Y_SERVICE_CAPABILITY); 240 updateServiceInfo(mSpyServiceInfo, 0, 0, A11Y_SERVICE_FLAG, null, 0); 241 242 mServiceConnection = new TestAccessibilityServiceConnection(mMockContext, COMPONENT_NAME, 243 mSpyServiceInfo, SERVICE_ID, mHandler, new Object(), mMockSecurityPolicy, 244 mMockSystemSupport, mMockA11yTrace, mMockWindowManagerInternal, 245 mMockSystemActionPerformer, mMockA11yWindowManager); 246 // Assume that the service is connected 247 mServiceConnection.mService = mMockService; 248 mServiceConnection.mServiceInterface = mMockServiceInterface; 249 250 // Update security policy for this service 251 when(mMockSecurityPolicy.checkAccessibilityAccess(mServiceConnection)).thenReturn(true); 252 when(mMockSecurityPolicy.canRetrieveWindowsLocked(mServiceConnection)).thenReturn(true); 253 when(mMockSecurityPolicy.canGetAccessibilityNodeInfoLocked( 254 eq(USER_ID), eq(mServiceConnection), anyInt())).thenReturn(true); 255 when(mMockSecurityPolicy.canControlMagnification(mServiceConnection)).thenReturn(true); 256 257 // init test functions for accessAccessibilityNodeInfo test case. 258 initTestFunctions(); 259 } 260 261 @Test getCapabilities()262 public void getCapabilities() { 263 assertThat(mServiceConnection.getCapabilities(), is(A11Y_SERVICE_CAPABILITY)); 264 } 265 266 @Test onKeyEvent()267 public void onKeyEvent() throws RemoteException { 268 final int sequenceNumber = 100; 269 final KeyEvent mockKeyEvent = mock(KeyEvent.class); 270 271 mServiceConnection.onKeyEvent(mockKeyEvent, sequenceNumber); 272 verify(mMockServiceInterface).onKeyEvent(mockKeyEvent, sequenceNumber); 273 } 274 275 @Test setServiceInfo_invokeOnClientChange()276 public void setServiceInfo_invokeOnClientChange() { 277 final AccessibilityServiceInfo serviceInfo = new AccessibilityServiceInfo(); 278 updateServiceInfo(serviceInfo, 279 TYPE_VIEW_CLICKED | TYPE_VIEW_LONG_CLICKED, 280 FEEDBACK_SPOKEN | FEEDBACK_HAPTIC, 281 A11Y_SERVICE_FLAG, 282 new String[] {PACKAGE_NAME1, PACKAGE_NAME2}, 283 1000); 284 285 mServiceConnection.setServiceInfo(serviceInfo); 286 verify(mMockSystemSupport).onClientChangeLocked(true); 287 } 288 289 @Test setServiceInfo_ChangePackageNames_updateSuccess()290 public void setServiceInfo_ChangePackageNames_updateSuccess() { 291 assertTrue(mServiceConnection.mPackageNames.isEmpty()); 292 293 final AccessibilityServiceInfo serviceInfo = new AccessibilityServiceInfo(); 294 updateServiceInfo(serviceInfo, 0, 0, A11Y_SERVICE_FLAG, 295 new String[] {PACKAGE_NAME1, PACKAGE_NAME2}, 296 1000); 297 298 mServiceConnection.setServiceInfo(serviceInfo); 299 assertEquals(serviceInfo.packageNames.length, mServiceConnection.mPackageNames.size()); 300 assertTrue(mServiceConnection.mPackageNames.containsAll( 301 Arrays.asList(mServiceConnection.getServiceInfo().packageNames))); 302 303 updateServiceInfo(serviceInfo, 0, 0, A11Y_SERVICE_FLAG, null, 1000); 304 mServiceConnection.setServiceInfo(serviceInfo); 305 assertTrue(mServiceConnection.mPackageNames.isEmpty()); 306 } 307 308 @Test setServiceInfo_ChangeAccessibilityTool_updateFails()309 public void setServiceInfo_ChangeAccessibilityTool_updateFails() { 310 assertFalse(mSpyServiceInfo.isAccessibilityTool()); 311 312 final AccessibilityServiceInfo serviceInfo = new AccessibilityServiceInfo(); 313 serviceInfo.setAccessibilityTool(true); 314 mServiceConnection.setServiceInfo(serviceInfo); 315 316 // isAccessibilityTool should not be dynamically updatable 317 assertFalse(mSpyServiceInfo.isAccessibilityTool()); 318 } 319 320 @Test canReceiveEvents_hasEventType_returnTrue()321 public void canReceiveEvents_hasEventType_returnTrue() { 322 final AccessibilityServiceInfo serviceInfo = new AccessibilityServiceInfo(); 323 updateServiceInfo(serviceInfo, 324 TYPE_VIEW_CLICKED | TYPE_VIEW_LONG_CLICKED, 0, 325 0, null, 0); 326 327 mServiceConnection.setServiceInfo(serviceInfo); 328 assertThat(mServiceConnection.canReceiveEventsLocked(), is(true)); 329 } 330 331 @Test setOnKeyEventResult()332 public void setOnKeyEventResult() { 333 final int sequenceNumber = 100; 334 final boolean handled = true; 335 mServiceConnection.setOnKeyEventResult(handled, sequenceNumber); 336 337 verify(mMockKeyEventDispatcher).setOnKeyEventResult( 338 mServiceConnection, handled, sequenceNumber); 339 } 340 341 @Test getWindows()342 public void getWindows() { 343 final AccessibilityWindowInfo.WindowListSparseArray allWindows = 344 mServiceConnection.getWindows(); 345 346 assertEquals(2, allWindows.size()); 347 assertThat(allWindows.get(Display.DEFAULT_DISPLAY), is(mA11yWindowInfos)); 348 assertEquals(2, allWindows.get(Display.DEFAULT_DISPLAY).size()); 349 assertThat(allWindows.get(SECONDARY_DISPLAY_ID), is(mA11yWindowInfosOnSecondDisplay)); 350 assertEquals(1, allWindows.get(SECONDARY_DISPLAY_ID).size()); 351 } 352 353 @Test getWindows_returnNull()354 public void getWindows_returnNull() { 355 // no canRetrieveWindows, should return null 356 when(mMockSecurityPolicy.canRetrieveWindowsLocked(mServiceConnection)).thenReturn(false); 357 assertThat(mServiceConnection.getWindows(), is(nullValue())); 358 359 // no checkAccessibilityAccess, should return null 360 when(mMockSecurityPolicy.canRetrieveWindowsLocked(mServiceConnection)).thenReturn(true); 361 when(mMockSecurityPolicy.checkAccessibilityAccess(mServiceConnection)).thenReturn(false); 362 assertThat(mServiceConnection.getWindows(), is(nullValue())); 363 } 364 365 @Test getWindows_notTrackingWindows_invokeOnClientChange()366 public void getWindows_notTrackingWindows_invokeOnClientChange() { 367 when(mMockA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY)).thenReturn(null); 368 when(mMockA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY)) 369 .thenReturn(false); 370 371 mServiceConnection.getWindows(); 372 verify(mMockSystemSupport).onClientChangeLocked(false); 373 } 374 375 @Test getWindow()376 public void getWindow() { 377 assertThat(mServiceConnection.getWindow(WINDOWID), is(mA11yWindowInfos.get(0))); 378 } 379 380 @Test getWindow_returnNull()381 public void getWindow_returnNull() { 382 // no canRetrieveWindows, should return null 383 when(mMockSecurityPolicy.canRetrieveWindowsLocked(mServiceConnection)).thenReturn(false); 384 assertThat(mServiceConnection.getWindow(WINDOWID), is(nullValue())); 385 386 // no checkAccessibilityAccess, should return null 387 when(mMockSecurityPolicy.canRetrieveWindowsLocked(mServiceConnection)).thenReturn(true); 388 when(mMockSecurityPolicy.checkAccessibilityAccess(mServiceConnection)).thenReturn(false); 389 assertThat(mServiceConnection.getWindow(WINDOWID), is(nullValue())); 390 } 391 392 @Test getWindow_notTrackingWindows_invokeOnClientChange()393 public void getWindow_notTrackingWindows_invokeOnClientChange() { 394 when(mMockA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY)).thenReturn(null); 395 when(mMockA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY)) 396 .thenReturn(false); 397 398 mServiceConnection.getWindow(WINDOWID); 399 verify(mMockSystemSupport).onClientChangeLocked(false); 400 } 401 402 @Test getWindow_onNonDefaultDisplay()403 public void getWindow_onNonDefaultDisplay() { 404 assertThat(mServiceConnection.getWindow(WINDOWID_ONSECONDDISPLAY), 405 is(mA11yWindowInfosOnSecondDisplay.get(0))); 406 } 407 408 @Test accessAccessibilityNodeInfo_whenCantGetInfo_returnNullOrFalse()409 public void accessAccessibilityNodeInfo_whenCantGetInfo_returnNullOrFalse() 410 throws Exception { 411 when(mMockSecurityPolicy.canGetAccessibilityNodeInfoLocked( 412 USER_ID, mServiceConnection, WINDOWID)).thenReturn(false); 413 for (int i = 0; i < mFindA11yNodesFunctions.length; i++) { 414 assertThat(mFindA11yNodesFunctions[i].call(), is(nullValue())); 415 } 416 assertThat(mPerformA11yAction.call(), is(false)); 417 418 verifyNoMoreInteractions(mMockIA11yInteractionConnection); 419 verify(mMockSecurityPolicy, never()).computeValidReportedPackages(any(), anyInt()); 420 } 421 422 @Test accessAccessibilityNodeInfo_whenNoA11yAccess_returnNullOrFalse()423 public void accessAccessibilityNodeInfo_whenNoA11yAccess_returnNullOrFalse() 424 throws Exception { 425 when(mMockSecurityPolicy.checkAccessibilityAccess(mServiceConnection)).thenReturn(false); 426 for (int i = 0; i < mFindA11yNodesFunctions.length; i++) { 427 assertThat(mFindA11yNodesFunctions[i].call(), is(nullValue())); 428 } 429 assertThat(mPerformA11yAction.call(), is(false)); 430 431 verifyNoMoreInteractions(mMockIA11yInteractionConnection); 432 verify(mMockSecurityPolicy, never()).computeValidReportedPackages(any(), anyInt()); 433 } 434 435 @Test accessAccessibilityNodeInfo_whenNoRemoteA11yConnection_returnNullOrFalse()436 public void accessAccessibilityNodeInfo_whenNoRemoteA11yConnection_returnNullOrFalse() 437 throws Exception { 438 when(mMockA11yWindowManager.getConnectionLocked(USER_ID, WINDOWID)).thenReturn(null); 439 for (int i = 0; i < mFindA11yNodesFunctions.length; i++) { 440 assertThat(mFindA11yNodesFunctions[i].call(), is(nullValue())); 441 } 442 assertThat(mPerformA11yAction.call(), is(false)); 443 444 verifyNoMoreInteractions(mMockIA11yInteractionConnection); 445 verify(mMockSecurityPolicy, never()).computeValidReportedPackages(any(), anyInt()); 446 } 447 448 @Test findAccessibilityNodeInfosByViewId_withPipWindow_shouldReplaceCallback()449 public void findAccessibilityNodeInfosByViewId_withPipWindow_shouldReplaceCallback() 450 throws RemoteException { 451 final ArgumentCaptor<IAccessibilityInteractionConnectionCallback> captor = 452 ArgumentCaptor.forClass(IAccessibilityInteractionConnectionCallback.class); 453 mServiceConnection.findAccessibilityNodeInfosByViewId(PIP_WINDOWID, ROOT_NODE_ID, 454 VIEWID_RESOURCE_NAME, INTERACTION_ID, mMockCallback, TID); 455 verify(mMockIA11yInteractionConnection).findAccessibilityNodeInfosByViewId( 456 eq(ROOT_NODE_ID), eq(VIEWID_RESOURCE_NAME), any(), eq(INTERACTION_ID), 457 captor.capture(), anyInt(), eq(PID), eq(TID), any(), nullable(float[].class)); 458 verify(mMockSecurityPolicy).computeValidReportedPackages(any(), anyInt()); 459 verifyReplaceActions(captor.getValue()); 460 } 461 462 @Test findAccessibilityNodeInfosByText_withPipWindow_shouldReplaceCallback()463 public void findAccessibilityNodeInfosByText_withPipWindow_shouldReplaceCallback() 464 throws RemoteException { 465 final ArgumentCaptor<IAccessibilityInteractionConnectionCallback> captor = 466 ArgumentCaptor.forClass(IAccessibilityInteractionConnectionCallback.class); 467 mServiceConnection.findAccessibilityNodeInfosByText(PIP_WINDOWID, ROOT_NODE_ID, 468 VIEW_TEXT, INTERACTION_ID, mMockCallback, TID); 469 verify(mMockIA11yInteractionConnection).findAccessibilityNodeInfosByText( 470 eq(ROOT_NODE_ID), eq(VIEW_TEXT), any(), eq(INTERACTION_ID), 471 captor.capture(), anyInt(), eq(PID), eq(TID), any(), nullable(float[].class)); 472 verify(mMockSecurityPolicy).computeValidReportedPackages(any(), anyInt()); 473 verifyReplaceActions(captor.getValue()); 474 } 475 476 @Test findAccessibilityNodeInfoByAccessibilityId_withPipWindow_shouldReplaceCallback()477 public void findAccessibilityNodeInfoByAccessibilityId_withPipWindow_shouldReplaceCallback() 478 throws RemoteException { 479 final ArgumentCaptor<IAccessibilityInteractionConnectionCallback> captor = 480 ArgumentCaptor.forClass(IAccessibilityInteractionConnectionCallback.class); 481 mServiceConnection.findAccessibilityNodeInfoByAccessibilityId(PIP_WINDOWID, ROOT_NODE_ID, 482 INTERACTION_ID, mMockCallback, 0, TID, null); 483 verify(mMockIA11yInteractionConnection).findAccessibilityNodeInfoByAccessibilityId( 484 eq(ROOT_NODE_ID), any(), eq(INTERACTION_ID), captor.capture(), anyInt(), 485 eq(PID), eq(TID), any(), nullable(float[].class), any()); 486 verify(mMockSecurityPolicy).computeValidReportedPackages(any(), anyInt()); 487 verifyReplaceActions(captor.getValue()); 488 } 489 490 @Test findFocus_withPipWindow_shouldReplaceCallback()491 public void findFocus_withPipWindow_shouldReplaceCallback() 492 throws RemoteException { 493 final ArgumentCaptor<IAccessibilityInteractionConnectionCallback> captor = 494 ArgumentCaptor.forClass(IAccessibilityInteractionConnectionCallback.class); 495 mServiceConnection.findFocus(PIP_WINDOWID, ROOT_NODE_ID, FOCUS_INPUT, INTERACTION_ID, 496 mMockCallback, TID); 497 verify(mMockIA11yInteractionConnection).findFocus(eq(ROOT_NODE_ID), eq(FOCUS_INPUT), 498 any(), eq(INTERACTION_ID), captor.capture(), anyInt(), eq(PID), eq(TID), any(), 499 nullable(float[].class)); 500 verify(mMockSecurityPolicy).computeValidReportedPackages(any(), anyInt()); 501 verifyReplaceActions(captor.getValue()); 502 } 503 504 @Test focusSearch_withPipWindow_shouldReplaceCallback()505 public void focusSearch_withPipWindow_shouldReplaceCallback() 506 throws RemoteException { 507 final ArgumentCaptor<IAccessibilityInteractionConnectionCallback> captor = 508 ArgumentCaptor.forClass(IAccessibilityInteractionConnectionCallback.class); 509 mServiceConnection.focusSearch(PIP_WINDOWID, ROOT_NODE_ID, FOCUS_DOWN, INTERACTION_ID, 510 mMockCallback, TID); 511 verify(mMockIA11yInteractionConnection).focusSearch(eq(ROOT_NODE_ID), eq(FOCUS_DOWN), 512 any(), eq(INTERACTION_ID), captor.capture(), anyInt(), eq(PID), eq(TID), any(), 513 nullable(float[].class)); 514 verify(mMockSecurityPolicy).computeValidReportedPackages(any(), anyInt()); 515 verifyReplaceActions(captor.getValue()); 516 } 517 518 @Test performAccessibilityAction_withPipWindow_invokeGetPipReplacingConnection()519 public void performAccessibilityAction_withPipWindow_invokeGetPipReplacingConnection() 520 throws RemoteException { 521 mServiceConnection.performAccessibilityAction(PIP_WINDOWID, ROOT_NODE_ID, 522 ACTION_ACCESSIBILITY_FOCUS, null, INTERACTION_ID, mMockCallback, TID); 523 524 verify(mMockIPowerManager).userActivity(eq(Display.DEFAULT_DISPLAY), anyLong(), anyInt(), 525 anyInt()); 526 verify(mMockIA11yInteractionConnection).performAccessibilityAction(eq(ROOT_NODE_ID), 527 eq(ACTION_ACCESSIBILITY_FOCUS), any(), eq(INTERACTION_ID), eq(mMockCallback), 528 anyInt(), eq(PID), eq(TID)); 529 verify(mMockA11yWindowManager).getPictureInPictureActionReplacingConnection(); 530 } 531 532 @Test performAccessibilityAction_withClick_shouldNotifyOutsideTouch()533 public void performAccessibilityAction_withClick_shouldNotifyOutsideTouch() 534 throws RemoteException { 535 mServiceConnection.performAccessibilityAction(WINDOWID, ROOT_NODE_ID, 536 ACTION_CLICK, null, INTERACTION_ID, mMockCallback, TID); 537 mServiceConnection.performAccessibilityAction(PIP_WINDOWID, ROOT_NODE_ID, 538 ACTION_LONG_CLICK, null, INTERACTION_ID, mMockCallback, TID); 539 verify(mMockA11yWindowManager).notifyOutsideTouch(eq(USER_ID), eq(WINDOWID)); 540 verify(mMockA11yWindowManager).notifyOutsideTouch(eq(USER_ID), eq(PIP_WINDOWID)); 541 } 542 543 @Test performGlobalAction()544 public void performGlobalAction() { 545 mServiceConnection.performGlobalAction(GLOBAL_ACTION_HOME); 546 verify(mMockSystemActionPerformer).performSystemAction(GLOBAL_ACTION_HOME); 547 } 548 549 @Test getSystemActions()550 public void getSystemActions() { 551 List<AccessibilityNodeInfo.AccessibilityAction> actions = 552 mServiceConnection.getSystemActions(); 553 verify(mMockSystemActionPerformer).getSystemActions(); 554 } 555 556 @Test isFingerprintGestureDetectionAvailable_hasFingerPrintSupport_returnTrue()557 public void isFingerprintGestureDetectionAvailable_hasFingerPrintSupport_returnTrue() { 558 when(mMockFingerprintGestureDispatcher.isFingerprintGestureDetectionAvailable()) 559 .thenReturn(true); 560 final boolean result = mServiceConnection.isFingerprintGestureDetectionAvailable(); 561 assertThat(result, is(true)); 562 } 563 564 @Test isFingerprintGestureDetectionAvailable_noFingerPrintSupport_returnFalse()565 public void isFingerprintGestureDetectionAvailable_noFingerPrintSupport_returnFalse() { 566 when(mMockFingerprintGestureDispatcher.isFingerprintGestureDetectionAvailable()) 567 .thenReturn(true); 568 569 // Return false if device does not support fingerprint 570 when(mMockPackageManager.hasSystemFeature(FEATURE_FINGERPRINT)).thenReturn(false); 571 boolean result = mServiceConnection.isFingerprintGestureDetectionAvailable(); 572 assertThat(result, is(false)); 573 574 // Return false if service does not have flag 575 when(mMockPackageManager.hasSystemFeature(FEATURE_FINGERPRINT)).thenReturn(true); 576 mSpyServiceInfo.flags = A11Y_SERVICE_FLAG & ~FLAG_REQUEST_FINGERPRINT_GESTURES; 577 mServiceConnection.setServiceInfo(mSpyServiceInfo); 578 result = mServiceConnection.isFingerprintGestureDetectionAvailable(); 579 assertThat(result, is(false)); 580 } 581 582 @Test getMagnificationScale()583 public void getMagnificationScale() { 584 final int displayId = 1; 585 final float scale = 2.0f; 586 when(mMockMagnificationProcessor.getScale(displayId)).thenReturn(scale); 587 588 final float result = mServiceConnection.getMagnificationScale(displayId); 589 assertThat(result, is(scale)); 590 } 591 592 @Test getMagnificationScale_serviceNotBelongCurrentUser_returnNoScale()593 public void getMagnificationScale_serviceNotBelongCurrentUser_returnNoScale() { 594 final int displayId = 1; 595 final float scale = 2.0f; 596 when(mMockMagnificationProcessor.getScale(displayId)).thenReturn(scale); 597 when(mMockSystemSupport.getCurrentUserIdLocked()).thenReturn(USER_ID2); 598 599 final float result = mServiceConnection.getMagnificationScale(displayId); 600 assertThat(result, is(1.0f)); 601 } 602 603 @Test getMagnificationRegion_serviceNotBelongCurrentUser_returnEmptyRegion()604 public void getMagnificationRegion_serviceNotBelongCurrentUser_returnEmptyRegion() { 605 final int displayId = 1; 606 final Region region = new Region(10, 20, 100, 200); 607 doAnswer((invocation) -> { 608 ((Region) invocation.getArguments()[1]).set(region); 609 return null; 610 }).when(mMockMagnificationProcessor).getFullscreenMagnificationRegion(eq(displayId), any(), 611 anyBoolean()); 612 when(mMockSystemSupport.getCurrentUserIdLocked()).thenReturn(USER_ID2); 613 614 final Region result = mServiceConnection.getMagnificationRegion(displayId); 615 assertThat(result.isEmpty(), is(true)); 616 } 617 618 @Test getCurrentMagnificationRegion_returnRegion()619 public void getCurrentMagnificationRegion_returnRegion() { 620 final int displayId = 1; 621 final Region region = new Region(10, 20, 100, 200); 622 doAnswer((invocation) -> { 623 ((Region) invocation.getArguments()[1]).set(region); 624 return null; 625 }).when(mMockMagnificationProcessor).getCurrentMagnificationRegion(eq(displayId), any(), 626 anyBoolean()); 627 628 final Region result = mServiceConnection.getCurrentMagnificationRegion(displayId); 629 assertEquals(result, region); 630 } 631 632 @Test getMagnificationCenterX_serviceNotBelongCurrentUser_returnZero()633 public void getMagnificationCenterX_serviceNotBelongCurrentUser_returnZero() { 634 final int displayId = 1; 635 final float centerX = 480.0f; 636 when(mMockMagnificationProcessor.getCenterX(displayId, /* canControlMagnification= */ 637 true)).thenReturn(centerX); 638 when(mMockSystemSupport.getCurrentUserIdLocked()).thenReturn(USER_ID2); 639 640 final float result = mServiceConnection.getMagnificationCenterX(displayId); 641 assertThat(result, is(0.0f)); 642 } 643 644 @Test getMagnificationCenterY_serviceNotBelongCurrentUser_returnZero()645 public void getMagnificationCenterY_serviceNotBelongCurrentUser_returnZero() { 646 final int displayId = 1; 647 final float centerY = 640.0f; 648 when(mMockMagnificationProcessor.getCenterY(displayId, /* canControlMagnification= */ 649 true)).thenReturn(centerY); 650 when(mMockSystemSupport.getCurrentUserIdLocked()).thenReturn(USER_ID2); 651 652 final float result = mServiceConnection.getMagnificationCenterY(displayId); 653 assertThat(result, is(0.0f)); 654 } 655 656 @Test resetMagnification()657 public void resetMagnification() { 658 final int displayId = 1; 659 when(mMockMagnificationProcessor.resetFullscreenMagnification(displayId, true)).thenReturn( 660 true); 661 662 final boolean result = mServiceConnection.resetMagnification(displayId, true); 663 assertThat(result, is(true)); 664 } 665 666 @Test resetMagnification_cantControlMagnification_returnFalse()667 public void resetMagnification_cantControlMagnification_returnFalse() { 668 final int displayId = 1; 669 when(mMockMagnificationProcessor.resetFullscreenMagnification(displayId, true)).thenReturn( 670 true); 671 when(mMockSecurityPolicy.canControlMagnification(mServiceConnection)).thenReturn(false); 672 673 final boolean result = mServiceConnection.resetMagnification(displayId, true); 674 assertThat(result, is(false)); 675 } 676 677 @Test resetMagnification_serviceNotBelongCurrentUser_returnFalse()678 public void resetMagnification_serviceNotBelongCurrentUser_returnFalse() { 679 final int displayId = 1; 680 when(mMockMagnificationProcessor.resetFullscreenMagnification(displayId, true)).thenReturn( 681 true); 682 when(mMockSystemSupport.getCurrentUserIdLocked()).thenReturn(USER_ID2); 683 684 final boolean result = mServiceConnection.resetMagnification(displayId, true); 685 assertThat(result, is(false)); 686 } 687 688 @Test setMagnificationConfig_cantControlMagnification_returnFalse()689 public void setMagnificationConfig_cantControlMagnification_returnFalse() { 690 final int displayId = 1; 691 final float scale = 1.8f; 692 final float centerX = 50.5f; 693 final float centerY = 100.5f; 694 MagnificationConfig config = new MagnificationConfig.Builder() 695 .setScale(scale) 696 .setCenterX(centerX) 697 .setCenterY(centerY).build(); 698 when(mMockMagnificationProcessor.setMagnificationConfig(displayId, config, true, 699 SERVICE_ID)).thenReturn(true); 700 when(mMockSecurityPolicy.canControlMagnification(mServiceConnection)).thenReturn(false); 701 702 final boolean result = mServiceConnection.setMagnificationConfig(displayId, config, true); 703 assertFalse(result); 704 } 705 706 @Test setMagnificationConfig_serviceNotBelongCurrentUser_returnFalse()707 public void setMagnificationConfig_serviceNotBelongCurrentUser_returnFalse() { 708 final int displayId = 1; 709 final float scale = 1.8f; 710 final float centerX = 50.5f; 711 final float centerY = 100.5f; 712 MagnificationConfig config = new MagnificationConfig.Builder() 713 .setScale(scale) 714 .setCenterX(centerX) 715 .setCenterY(centerY).build(); 716 when(mMockMagnificationProcessor.setMagnificationConfig(displayId, config, true, 717 SERVICE_ID)).thenReturn(true); 718 when(mMockSystemSupport.getCurrentUserIdLocked()).thenReturn(USER_ID2); 719 720 final boolean result = mServiceConnection.setMagnificationConfig(displayId, config, true); 721 assertFalse(result); 722 } 723 724 @Test (expected = SecurityException.class) takeScreenshot_withoutCapability_throwSecurityException()725 public void takeScreenshot_withoutCapability_throwSecurityException() { 726 // no canTakeScreenshot, should throw security exception. 727 when(mMockSecurityPolicy.canTakeScreenshotLocked(mServiceConnection)).thenReturn(false); 728 mServiceConnection.takeScreenshot(Display.DEFAULT_DISPLAY, new RemoteCallback((result) -> { 729 })); 730 } 731 732 @Test takeScreenshot_NoA11yAccess_returnErrorCode()733 public void takeScreenshot_NoA11yAccess_returnErrorCode() throws InterruptedException { 734 // no checkAccessibilityAccess, should return error code. 735 when(mMockSecurityPolicy.canTakeScreenshotLocked(mServiceConnection)).thenReturn(true); 736 when(mMockSecurityPolicy.checkAccessibilityAccess(mServiceConnection)).thenReturn(false); 737 738 mServiceConnection.takeScreenshot(Display.DEFAULT_DISPLAY, 739 new RemoteCallback(mMockListener)); 740 mHandler.sendLastMessage(); 741 742 verify(mMockListener).onResult(Mockito.argThat( 743 bundle -> ERROR_TAKE_SCREENSHOT_NO_ACCESSIBILITY_ACCESS 744 == bundle.getInt(KEY_ACCESSIBILITY_SCREENSHOT_STATUS))); 745 } 746 747 @Test takeScreenshot_invalidDisplay_returnErrorCode()748 public void takeScreenshot_invalidDisplay_returnErrorCode() throws InterruptedException { 749 when(mMockSecurityPolicy.canTakeScreenshotLocked(mServiceConnection)).thenReturn(true); 750 when(mMockSecurityPolicy.checkAccessibilityAccess(mServiceConnection)).thenReturn(true); 751 752 final DisplayManager displayManager = new DisplayManager(mMockContext); 753 when(mMockContext.getSystemService(Context.DISPLAY_SERVICE)).thenReturn(displayManager); 754 755 mServiceConnection.takeScreenshot(Display.DEFAULT_DISPLAY + 1, 756 new RemoteCallback(mMockListener)); 757 mHandler.sendLastMessage(); 758 759 verify(mMockListener).onResult(Mockito.argThat( 760 bundle -> ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY 761 == bundle.getInt(KEY_ACCESSIBILITY_SCREENSHOT_STATUS))); 762 } 763 updateServiceInfo(AccessibilityServiceInfo serviceInfo, int eventType, int feedbackType, int flags, String[] packageNames, int notificationTimeout)764 private void updateServiceInfo(AccessibilityServiceInfo serviceInfo, int eventType, 765 int feedbackType, int flags, String[] packageNames, int notificationTimeout) { 766 serviceInfo.eventTypes = eventType; 767 serviceInfo.feedbackType = feedbackType; 768 serviceInfo.flags = flags; 769 serviceInfo.packageNames = packageNames; 770 serviceInfo.notificationTimeout = notificationTimeout; 771 } 772 addA11yWindowInfo(List<AccessibilityWindowInfo> infos, int windowId, boolean isPip, int displayId)773 private AccessibilityWindowInfo addA11yWindowInfo(List<AccessibilityWindowInfo> infos, 774 int windowId, boolean isPip, int displayId) { 775 final AccessibilityWindowInfo info = AccessibilityWindowInfo.obtain(); 776 info.setId(windowId); 777 info.setDisplayId(displayId); 778 info.setPictureInPicture(isPip); 779 infos.add(info); 780 return info; 781 } 782 getRemoteA11yConnection(int windowId, IAccessibilityInteractionConnection connection, String packageName)783 private RemoteAccessibilityConnection getRemoteA11yConnection(int windowId, 784 IAccessibilityInteractionConnection connection, 785 String packageName) { 786 return mMockA11yWindowManager.new RemoteAccessibilityConnection( 787 windowId, connection, packageName, UID, USER_ID); 788 } 789 initTestFunctions()790 private void initTestFunctions() { 791 // Init functions for accessibility nodes finding and searching by different filter rules. 792 // We group them together for the tests because they have similar implementation. 793 mFindA11yNodesFunctions = new Callable[] { 794 // findAccessibilityNodeInfosByViewId 795 () -> mServiceConnection.findAccessibilityNodeInfosByViewId(WINDOWID, 796 ROOT_NODE_ID, VIEWID_RESOURCE_NAME, INTERACTION_ID, 797 mMockCallback, TID), 798 // findAccessibilityNodeInfosByText 799 () -> mServiceConnection.findAccessibilityNodeInfosByText(WINDOWID, 800 ROOT_NODE_ID, VIEW_TEXT, INTERACTION_ID, mMockCallback, TID), 801 // findAccessibilityNodeInfoByAccessibilityId 802 () -> mServiceConnection.findAccessibilityNodeInfoByAccessibilityId(WINDOWID, 803 ROOT_NODE_ID, INTERACTION_ID, mMockCallback, 0, TID, null), 804 // findFocus 805 () -> mServiceConnection.findFocus(WINDOWID, ROOT_NODE_ID, FOCUS_INPUT, 806 INTERACTION_ID, mMockCallback, TID), 807 // focusSearch 808 () -> mServiceConnection.focusSearch(WINDOWID, ROOT_NODE_ID, FOCUS_DOWN, 809 INTERACTION_ID, mMockCallback, TID) 810 }; 811 // performAccessibilityAction 812 mPerformA11yAction = () -> mServiceConnection.performAccessibilityAction(WINDOWID, 813 ROOT_NODE_ID, ACTION_ACCESSIBILITY_FOCUS, null, INTERACTION_ID, 814 mMockCallback, TID); 815 } 816 verifyReplaceActions(IAccessibilityInteractionConnectionCallback replacedCallback)817 private void verifyReplaceActions(IAccessibilityInteractionConnectionCallback replacedCallback) 818 throws RemoteException { 819 final AccessibilityNodeInfo nodeFromApp = AccessibilityNodeInfo.obtain(); 820 nodeFromApp.setSourceNodeId(AccessibilityNodeInfo.ROOT_NODE_ID, WINDOWID); 821 822 final AccessibilityNodeInfo nodeFromReplacer = AccessibilityNodeInfo.obtain(); 823 nodeFromReplacer.setSourceNodeId(AccessibilityNodeInfo.ROOT_NODE_ID, 824 AccessibilityWindowInfo.PICTURE_IN_PICTURE_ACTION_REPLACER_WINDOW_ID); 825 nodeFromReplacer.addAction(AccessibilityAction.ACTION_CLICK); 826 nodeFromReplacer.addAction(AccessibilityAction.ACTION_EXPAND); 827 final List<AccessibilityNodeInfo> replacerList = Arrays.asList(nodeFromReplacer); 828 829 replacedCallback.setFindAccessibilityNodeInfoResult(nodeFromApp, INTERACTION_ID); 830 replacedCallback.setFindAccessibilityNodeInfosResult(replacerList, INTERACTION_ID + 1); 831 832 final ArgumentCaptor<AccessibilityNodeInfo> captor = 833 ArgumentCaptor.forClass(AccessibilityNodeInfo.class); 834 verify(mMockCallback).setFindAccessibilityNodeInfoResult(captor.capture(), 835 eq(INTERACTION_ID)); 836 assertThat(captor.getValue().getActionList(), 837 hasItems(AccessibilityAction.ACTION_CLICK, AccessibilityAction.ACTION_EXPAND)); 838 } 839 840 private static class TestAccessibilityServiceConnection 841 extends AbstractAccessibilityServiceConnection { 842 int mResolvedUserId; 843 TestAccessibilityServiceConnection(Context context, ComponentName componentName, AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler, Object lock, AccessibilitySecurityPolicy securityPolicy, SystemSupport systemSupport, AccessibilityTrace trace, WindowManagerInternal windowManagerInternal, SystemActionPerformer systemActionPerfomer, AccessibilityWindowManager a11yWindowManager)844 TestAccessibilityServiceConnection(Context context, ComponentName componentName, 845 AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler, 846 Object lock, AccessibilitySecurityPolicy securityPolicy, 847 SystemSupport systemSupport, AccessibilityTrace trace, 848 WindowManagerInternal windowManagerInternal, 849 SystemActionPerformer systemActionPerfomer, 850 AccessibilityWindowManager a11yWindowManager) { 851 super(context, componentName, accessibilityServiceInfo, id, mainHandler, lock, 852 securityPolicy, systemSupport, trace, windowManagerInternal, 853 systemActionPerfomer, a11yWindowManager); 854 mResolvedUserId = USER_ID; 855 } 856 857 @Override hasRightsToCurrentUserLocked()858 protected boolean hasRightsToCurrentUserLocked() { 859 return mResolvedUserId == mSystemSupport.getCurrentUserIdLocked(); 860 } 861 862 @Override disableSelf()863 public void disableSelf() throws RemoteException {} 864 865 @Override setSoftKeyboardShowMode(int showMode)866 public boolean setSoftKeyboardShowMode(int showMode) throws RemoteException { 867 return false; 868 } 869 870 @Override getSoftKeyboardShowMode()871 public int getSoftKeyboardShowMode() throws RemoteException { 872 return 0; 873 } 874 875 @Override switchToInputMethod(String imeId)876 public boolean switchToInputMethod(String imeId) { 877 return false; 878 } 879 880 @Override setInputMethodEnabled(String imeId, boolean enabled)881 public int setInputMethodEnabled(String imeId, boolean enabled) throws RemoteException { 882 return AccessibilityService.SoftKeyboardController.ENABLE_IME_FAIL_UNKNOWN; 883 } 884 885 @Override isAccessibilityButtonAvailable()886 public boolean isAccessibilityButtonAvailable() throws RemoteException { 887 return false; 888 } 889 890 @Override onServiceConnected(ComponentName name, IBinder service)891 public void onServiceConnected(ComponentName name, IBinder service) {} 892 893 @Override onServiceDisconnected(ComponentName name)894 public void onServiceDisconnected(ComponentName name) {} 895 896 @Override binderDied()897 public void binderDied() {} 898 899 @Override isCapturingFingerprintGestures()900 public boolean isCapturingFingerprintGestures() { 901 return mCaptureFingerprintGestures; 902 } 903 904 @Override onFingerprintGestureDetectionActiveChanged(boolean active)905 public void onFingerprintGestureDetectionActiveChanged(boolean active) {} 906 907 @Override onFingerprintGesture(int gesture)908 public void onFingerprintGesture(int gesture) {} 909 } 910 } 911