AccessibilityManagerServiceTest.java revision 383742c16d3dcbfcf748a89f0cb88ac8d2b31bb5
1344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.com/* 2344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.com * Copyright (C) 2010 The Android Open Source Project 3344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.com * 4344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.com * Licensed under the Apache License, Version 2.0 (the "License"); 5344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.com * you may not use this file except in compliance with the License. 6344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.com * You may obtain a copy of the License at 7344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.com * 8344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.com * http://www.apache.org/licenses/LICENSE-2.0 9344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.com * 10344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.com * Unless required by applicable law or agreed to in writing, software 11344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.com * distributed under the License is distributed on an "AS IS" BASIS, 12344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.com * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.com * See the License for the specific language governing permissions and 14344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.com * limitations under the License. 15344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.com */ 16344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.com 17344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.compackage com.android.server; 18344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.com 19344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.comimport android.accessibilityservice.AccessibilityService; 20344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.comimport android.accessibilityservice.AccessibilityServiceInfo; 21344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.comimport android.content.ComponentName; 22344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.comimport android.content.Context; 23344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.comimport android.content.pm.ServiceInfo; 24344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.comimport android.os.IBinder; 25344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.comimport android.os.Message; 26344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.comimport android.os.ServiceManager; 27344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.comimport android.os.SystemClock; 28344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.comimport android.provider.Settings; 29344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.comimport android.test.AndroidTestCase; 30344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.comimport android.test.suitebuilder.annotation.LargeTest; 31344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.comimport android.view.accessibility.AccessibilityEvent; 32344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.comimport android.view.accessibility.IAccessibilityManager; 33344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.comimport android.view.accessibility.IAccessibilityManagerClient; 34344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.com 35344caf0bfb20161349dbf2f658a7f096a08ea76plundblad@google.com/** 36 * This test exercises the 37 * {@link com.android.server.AccessibilityManagerService} by mocking the 38 * {@link android.view.accessibility.AccessibilityManager} which talks to to the 39 * service. The service itself is interacting with the platform. Note: Testing 40 * the service in full isolation would require significant amount of work for 41 * mocking all system interactions. It would also require a lot of mocking code. 42 */ 43public class AccessibilityManagerServiceTest extends AndroidTestCase { 44 45 /** 46 * Timeout required for pending Binder calls or event processing to 47 * complete. 48 */ 49 private static final long TIMEOUT_BINDER_CALL = 100; 50 51 /** 52 * Timeout in which we are waiting for the system to start the mock 53 * accessibility services. 54 */ 55 private static final long TIMEOUT_START_MOCK_ACCESSIBILITY_SERVICES = 300; 56 57 /** 58 * Timeout used for testing that a service is notified only upon a 59 * notification timeout. 60 */ 61 private static final long TIMEOUT_TEST_NOTIFICATION_TIMEOUT = 300; 62 63 /** 64 * The interface used to talk to the tested service. 65 */ 66 private IAccessibilityManager mManagerService; 67 68 @Override 69 public void setContext(Context context) { 70 super.setContext(context); 71 if (MyFirstMockAccessibilityService.sComponentName == null) { 72 MyFirstMockAccessibilityService.sComponentName = new ComponentName( 73 context.getPackageName(), MyFirstMockAccessibilityService.class.getName()) 74 .flattenToShortString(); 75 } 76 if (MySecondMockAccessibilityService.sComponentName == null) { 77 MySecondMockAccessibilityService.sComponentName = new ComponentName( 78 context.getPackageName(), MySecondMockAccessibilityService.class.getName()) 79 .flattenToShortString(); 80 } 81 } 82 83 /** 84 * Creates a new instance. 85 */ 86 public AccessibilityManagerServiceTest() { 87 IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE); 88 mManagerService = IAccessibilityManager.Stub.asInterface(iBinder); 89 } 90 91 @LargeTest 92 public void testAddClient_AccessibilityDisabledThenEnabled() throws Exception { 93 // make sure accessibility is disabled 94 ensureAccessibilityEnabled(mContext, false); 95 96 // create a client mock instance 97 MyMockAccessibilityManagerClient mockClient = new MyMockAccessibilityManagerClient(); 98 99 // invoke the method under test 100 boolean enabledAccessibilityDisabled = mManagerService.addClient(mockClient); 101 102 // check expected result 103 assertFalse("The client must be disabled since accessibility is disabled.", 104 enabledAccessibilityDisabled); 105 106 // enable accessibility 107 ensureAccessibilityEnabled(mContext, true); 108 109 // invoke the method under test 110 boolean enabledAccessibilityEnabled = mManagerService.addClient(mockClient); 111 112 // check expected result 113 assertTrue("The client must be enabled since accessibility is enabled.", 114 enabledAccessibilityEnabled); 115 } 116 117 @LargeTest 118 public void testAddClient_AccessibilityEnabledThenDisabled() throws Exception { 119 // enable accessibility before registering the client 120 ensureAccessibilityEnabled(mContext, true); 121 122 // create a client mock instance 123 MyMockAccessibilityManagerClient mockClient = new MyMockAccessibilityManagerClient(); 124 125 // invoke the method under test 126 boolean enabledAccessibilityEnabled = mManagerService.addClient(mockClient); 127 128 // check expected result 129 assertTrue("The client must be enabled since accessibility is enabled.", 130 enabledAccessibilityEnabled); 131 132 // disable accessibility 133 ensureAccessibilityEnabled(mContext, false); 134 135 // invoke the method under test 136 boolean enabledAccessibilityDisabled = mManagerService.addClient(mockClient); 137 138 // check expected result 139 assertFalse("The client must be disabled since accessibility is disabled.", 140 enabledAccessibilityDisabled); 141 } 142 143 @LargeTest 144 public void testGetAccessibilityServicesList() throws Exception { 145 boolean firstMockServiceInstalled = false; 146 boolean secondMockServiceInstalled = false; 147 148 String packageName = getContext().getPackageName(); 149 String firstMockServiceClassName = MyFirstMockAccessibilityService.class.getName(); 150 String secondMockServiceClassName = MySecondMockAccessibilityService.class.getName(); 151 152 // look for the two mock services 153 for (ServiceInfo serviceInfo : mManagerService.getAccessibilityServiceList()) { 154 if (packageName.equals(serviceInfo.packageName)) { 155 if (firstMockServiceClassName.equals(serviceInfo.name)) { 156 firstMockServiceInstalled = true; 157 } else if (secondMockServiceClassName.equals(serviceInfo.name)) { 158 secondMockServiceInstalled = true; 159 } 160 } 161 } 162 163 // check expected result 164 assertTrue("First mock service must be installed", firstMockServiceInstalled); 165 assertTrue("Second mock service must be installed", secondMockServiceInstalled); 166 } 167 168 @LargeTest 169 public void testSendAccessibilityEvent_OneService_MatchingPackageAndEventType() 170 throws Exception { 171 // set the accessibility setting value 172 ensureAccessibilityEnabled(mContext, true); 173 174 // enable the mock accessibility service 175 ensureOnlyMockServicesEnabled(mContext, true, false); 176 177 // configure the mock service 178 MockAccessibilityService service = MyFirstMockAccessibilityService.sInstance; 179 service.setServiceInfo(MockAccessibilityService.createDefaultInfo()); 180 181 // wait for the binder call to #setService to complete 182 Thread.sleep(TIMEOUT_BINDER_CALL); 183 184 // create and populate an event to be sent 185 AccessibilityEvent sentEvent = AccessibilityEvent.obtain(); 186 fullyPopulateDefaultAccessibilityEvent(sentEvent); 187 188 // set expectations 189 service.expectEvent(sentEvent); 190 service.replay(); 191 192 // send the event 193 mManagerService.sendAccessibilityEvent(sentEvent); 194 195 // verify if all expected methods have been called 196 assertMockServiceVerifiedWithinTimeout(service); 197 } 198 199 @LargeTest 200 public void testSendAccessibilityEvent_OneService_NotMatchingPackage() throws Exception { 201 // set the accessibility setting value 202 ensureAccessibilityEnabled(mContext, true); 203 204 // enable the mock accessibility service 205 ensureOnlyMockServicesEnabled(mContext, true, false); 206 207 // configure the mock service 208 MockAccessibilityService service = MyFirstMockAccessibilityService.sInstance; 209 service.setServiceInfo(MockAccessibilityService.createDefaultInfo()); 210 211 // wait for the binder call to #setService to complete 212 Thread.sleep(TIMEOUT_BINDER_CALL); 213 214 // create and populate an event to be sent 215 AccessibilityEvent sentEvent = AccessibilityEvent.obtain(); 216 fullyPopulateDefaultAccessibilityEvent(sentEvent); 217 sentEvent.setPackageName("no.service.registered.for.this.package"); 218 219 // set expectations 220 service.replay(); 221 222 // send the event 223 mManagerService.sendAccessibilityEvent(sentEvent); 224 225 // verify if all expected methods have been called 226 assertMockServiceVerifiedWithinTimeout(service); 227 } 228 229 @LargeTest 230 public void testSendAccessibilityEvent_OneService_NotMatchingEventType() throws Exception { 231 // set the accessibility setting value 232 ensureAccessibilityEnabled(mContext, true); 233 234 // enable the mock accessibility service 235 ensureOnlyMockServicesEnabled(mContext, true, false); 236 237 // configure the mock service 238 MockAccessibilityService service = MyFirstMockAccessibilityService.sInstance; 239 service.setServiceInfo(MockAccessibilityService.createDefaultInfo()); 240 241 // wait for the binder call to #setService to complete 242 Thread.sleep(TIMEOUT_BINDER_CALL); 243 244 // create and populate an event to be sent 245 AccessibilityEvent sentEvent = AccessibilityEvent.obtain(); 246 fullyPopulateDefaultAccessibilityEvent(sentEvent); 247 sentEvent.setEventType(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED); 248 249 // set expectations 250 service.replay(); 251 252 // send the event 253 mManagerService.sendAccessibilityEvent(sentEvent); 254 255 // verify if all expected methods have been called 256 assertMockServiceVerifiedWithinTimeout(service); 257 } 258 259 @LargeTest 260 public void testSendAccessibilityEvent_OneService_NotifivationAfterTimeout() throws Exception { 261 // set the accessibility setting value 262 ensureAccessibilityEnabled(mContext, true); 263 264 // enable the mock accessibility service 265 ensureOnlyMockServicesEnabled(mContext, true, false); 266 267 // configure the mock service 268 MockAccessibilityService service = MyFirstMockAccessibilityService.sInstance; 269 AccessibilityServiceInfo info = MockAccessibilityService.createDefaultInfo(); 270 info.notificationTimeout = TIMEOUT_TEST_NOTIFICATION_TIMEOUT; 271 service.setServiceInfo(info); 272 273 // wait for the binder call to #setService to complete 274 Thread.sleep(TIMEOUT_BINDER_CALL); 275 276 // create and populate the first event to be sent 277 AccessibilityEvent firstEvent = AccessibilityEvent.obtain(); 278 fullyPopulateDefaultAccessibilityEvent(firstEvent); 279 280 // create and populate the second event to be sent 281 AccessibilityEvent secondEvent = AccessibilityEvent.obtain(); 282 fullyPopulateDefaultAccessibilityEvent(secondEvent); 283 284 // set expectations 285 service.expectEvent(secondEvent); 286 service.replay(); 287 288 // send the events 289 mManagerService.sendAccessibilityEvent(firstEvent); 290 mManagerService.sendAccessibilityEvent(secondEvent); 291 292 // wait for #sendAccessibilityEvent to reach the backing service 293 Thread.sleep(TIMEOUT_BINDER_CALL); 294 295 try { 296 service.verify(); 297 fail("No events must be dispatched before the expiration of the notification timeout."); 298 } catch (IllegalStateException ise) { 299 /* expected */ 300 } 301 302 // wait for the configured notification timeout to expire 303 Thread.sleep(TIMEOUT_TEST_NOTIFICATION_TIMEOUT); 304 305 // verify if all expected methods have been called 306 assertMockServiceVerifiedWithinTimeout(service); 307 } 308 309 @LargeTest 310 public void testSendAccessibilityEvent_TwoServices_MatchingPackageAndEventType_DiffFeedback() 311 throws Exception { 312 // set the accessibility setting value 313 ensureAccessibilityEnabled(mContext, true); 314 315 // enable the mock accessibility services 316 ensureOnlyMockServicesEnabled(mContext, true, true); 317 318 // configure the first mock service 319 MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance; 320 AccessibilityServiceInfo firstInfo = MockAccessibilityService.createDefaultInfo(); 321 firstInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_AUDIBLE; 322 firstService.setServiceInfo(firstInfo); 323 324 // configure the second mock service 325 MockAccessibilityService secondService = MySecondMockAccessibilityService.sInstance; 326 AccessibilityServiceInfo secondInfo = MockAccessibilityService.createDefaultInfo(); 327 secondInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_HAPTIC; 328 secondService.setServiceInfo(secondInfo); 329 330 // wait for the binder calls to #setService to complete 331 Thread.sleep(TIMEOUT_BINDER_CALL); 332 333 // create and populate an event to be sent 334 AccessibilityEvent sentEvent = AccessibilityEvent.obtain(); 335 fullyPopulateDefaultAccessibilityEvent(sentEvent); 336 337 // set expectations for the first mock service 338 firstService.expectEvent(sentEvent); 339 firstService.replay(); 340 341 // set expectations for the second mock service 342 secondService.expectEvent(sentEvent); 343 secondService.replay(); 344 345 // send the event 346 mManagerService.sendAccessibilityEvent(sentEvent); 347 348 // verify if all expected methods have been called 349 assertMockServiceVerifiedWithinTimeout(firstService); 350 assertMockServiceVerifiedWithinTimeout(secondService); 351 } 352 353 @LargeTest 354 public void testSendAccessibilityEvent_TwoServices_MatchingPackageAndEventType() 355 throws Exception { 356 // set the accessibility setting value 357 ensureAccessibilityEnabled(mContext, true); 358 359 // enable the mock accessibility services 360 ensureOnlyMockServicesEnabled(mContext, true, true); 361 362 // configure the first mock service 363 MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance; 364 firstService.setServiceInfo(MockAccessibilityService.createDefaultInfo()); 365 366 // configure the second mock service 367 MockAccessibilityService secondService = MySecondMockAccessibilityService.sInstance; 368 secondService.setServiceInfo(MockAccessibilityService.createDefaultInfo()); 369 370 // wait for the binder calls to #setService to complete 371 Thread.sleep(TIMEOUT_BINDER_CALL); 372 373 // create and populate an event to be sent 374 AccessibilityEvent sentEvent = AccessibilityEvent.obtain(); 375 fullyPopulateDefaultAccessibilityEvent(sentEvent); 376 377 // set expectations for the first mock service 378 firstService.expectEvent(sentEvent); 379 firstService.replay(); 380 381 // set expectations for the second mock service 382 secondService.replay(); 383 384 // send the event 385 mManagerService.sendAccessibilityEvent(sentEvent); 386 387 // verify if all expected methods have been called 388 assertMockServiceVerifiedWithinTimeout(firstService); 389 assertMockServiceVerifiedWithinTimeout(secondService); 390 } 391 392 @LargeTest 393 public void testSendAccessibilityEvent_TwoServices_MatchingPackageAndEventType_OneDefault() 394 throws Exception { 395 // set the accessibility setting value 396 ensureAccessibilityEnabled(mContext, true); 397 398 // enable the mock accessibility services 399 ensureOnlyMockServicesEnabled(mContext, true, true); 400 401 // configure the first mock service 402 MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance; 403 AccessibilityServiceInfo firstInfo = MyFirstMockAccessibilityService.createDefaultInfo(); 404 firstInfo.flags = AccessibilityServiceInfo.DEFAULT; 405 firstService.setServiceInfo(firstInfo); 406 407 // configure the second mock service 408 MockAccessibilityService secondService = MySecondMockAccessibilityService.sInstance; 409 secondService.setServiceInfo(MySecondMockAccessibilityService.createDefaultInfo()); 410 411 // wait for the binder calls to #setService to complete 412 Thread.sleep(TIMEOUT_BINDER_CALL); 413 414 // create and populate an event to be sent 415 AccessibilityEvent sentEvent = AccessibilityEvent.obtain(); 416 fullyPopulateDefaultAccessibilityEvent(sentEvent); 417 418 // set expectations for the first mock service 419 firstService.replay(); 420 421 // set expectations for the second mock service 422 secondService.expectEvent(sentEvent); 423 secondService.replay(); 424 425 // send the event 426 mManagerService.sendAccessibilityEvent(sentEvent); 427 428 // verify if all expected methods have been called 429 assertMockServiceVerifiedWithinTimeout(firstService); 430 assertMockServiceVerifiedWithinTimeout(secondService); 431 } 432 433 @LargeTest 434 public void testSendAccessibilityEvent_TwoServices_MatchingPackageAndEventType_TwoDefault() 435 throws Exception { 436 // set the accessibility setting value 437 ensureAccessibilityEnabled(mContext, true); 438 439 // enable the mock accessibility services 440 ensureOnlyMockServicesEnabled(mContext, true, true); 441 442 // configure the first mock service 443 MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance; 444 AccessibilityServiceInfo firstInfo = MyFirstMockAccessibilityService.createDefaultInfo(); 445 firstInfo.flags = AccessibilityServiceInfo.DEFAULT; 446 firstService.setServiceInfo(firstInfo); 447 448 // configure the second mock service 449 MockAccessibilityService secondService = MySecondMockAccessibilityService.sInstance; 450 AccessibilityServiceInfo secondInfo = MyFirstMockAccessibilityService.createDefaultInfo(); 451 secondInfo.flags = AccessibilityServiceInfo.DEFAULT; 452 secondService.setServiceInfo(firstInfo); 453 454 // wait for the binder calls to #setService to complete 455 Thread.sleep(TIMEOUT_BINDER_CALL); 456 457 // create and populate an event to be sent 458 AccessibilityEvent sentEvent = AccessibilityEvent.obtain(); 459 fullyPopulateDefaultAccessibilityEvent(sentEvent); 460 461 // set expectations for the first mock service 462 firstService.expectEvent(sentEvent); 463 firstService.replay(); 464 465 // set expectations for the second mock service 466 secondService.replay(); 467 468 // send the event 469 mManagerService.sendAccessibilityEvent(sentEvent); 470 471 // verify if all expected methods have been called 472 assertMockServiceVerifiedWithinTimeout(firstService); 473 assertMockServiceVerifiedWithinTimeout(secondService); 474 } 475 476 @LargeTest 477 public void testInterrupt() throws Exception { 478 // set the accessibility setting value 479 ensureAccessibilityEnabled(mContext, true); 480 481 // enable the mock accessibility services 482 ensureOnlyMockServicesEnabled(mContext, true, true); 483 484 // configure the first mock service 485 MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance; 486 firstService.setServiceInfo(MockAccessibilityService.createDefaultInfo()); 487 488 // configure the second mock service 489 MockAccessibilityService secondService = MySecondMockAccessibilityService.sInstance; 490 secondService.setServiceInfo(MockAccessibilityService.createDefaultInfo()); 491 492 // wait for the binder calls to #setService to complete 493 Thread.sleep(TIMEOUT_BINDER_CALL); 494 495 // set expectations for the first mock service 496 firstService.expectInterrupt(); 497 firstService.replay(); 498 499 // set expectations for the second mock service 500 secondService.expectInterrupt(); 501 secondService.replay(); 502 503 // call the method under test 504 mManagerService.interrupt(); 505 506 // verify if all expected methods have been called 507 assertMockServiceVerifiedWithinTimeout(firstService); 508 assertMockServiceVerifiedWithinTimeout(secondService); 509 } 510 511 /** 512 * Fully populates the {@link AccessibilityEvent} to marshal. 513 * 514 * @param sentEvent The event to populate. 515 */ 516 private void fullyPopulateDefaultAccessibilityEvent(AccessibilityEvent sentEvent) { 517 sentEvent.setAddedCount(1); 518 sentEvent.setBeforeText("BeforeText"); 519 sentEvent.setChecked(true); 520 sentEvent.setClassName("foo.bar.baz.Class"); 521 sentEvent.setContentDescription("ContentDescription"); 522 sentEvent.setCurrentItemIndex(1); 523 sentEvent.setEnabled(true); 524 sentEvent.setEventType(AccessibilityEvent.TYPE_VIEW_CLICKED); 525 sentEvent.setEventTime(1000); 526 sentEvent.setFromIndex(1); 527 sentEvent.setFullScreen(true); 528 sentEvent.setItemCount(1); 529 sentEvent.setPackageName("foo.bar.baz"); 530 sentEvent.setParcelableData(Message.obtain(null, 1, null)); 531 sentEvent.setPassword(true); 532 sentEvent.setRemovedCount(1); 533 } 534 535 /** 536 * This class is a mock {@link IAccessibilityManagerClient}. 537 */ 538 public class MyMockAccessibilityManagerClient extends IAccessibilityManagerClient.Stub { 539 boolean mIsEnabled; 540 541 public void setEnabled(boolean enabled) { 542 mIsEnabled = enabled; 543 } 544 } 545 546 /** 547 * Ensures accessibility is in a given state by writing the state to the 548 * settings and waiting until the accessibility manager service pick it up. 549 * 550 * @param context A context handle to access the settings. 551 * @param enabled The accessibility state to write to the settings. 552 * @throws Exception If any error occurs. 553 */ 554 private void ensureAccessibilityEnabled(Context context, boolean enabled) throws Exception { 555 boolean isEnabled = (Settings.Secure.getInt(context.getContentResolver(), 556 Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1 ? true : false); 557 558 if (isEnabled == enabled) { 559 return; 560 } 561 562 Settings.Secure.putInt(context.getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED, 563 enabled ? 1 : 0); 564 565 // wait the accessibility manager service to pick the change up 566 Thread.sleep(TIMEOUT_BINDER_CALL); 567 } 568 569 /** 570 * Ensures the only {@link MockAccessibilityService}s with given component 571 * names are enabled by writing to the system settings and waiting until the 572 * accessibility manager service picks that up or the 573 * {@link #TIMEOUT_START_MOCK_ACCESSIBILITY_SERVICES} is exceeded. 574 * 575 * @param context A context handle to access the settings. 576 * @param firstMockServiceEnabled If the first mock accessibility service is enabled. 577 * @param secondMockServiceEnabled If the second mock accessibility service is enabled. 578 * @throws IllegalStateException If some of the requested for enabling mock services 579 * is not properly started. 580 * @throws Exception Exception If any error occurs. 581 */ 582 private void ensureOnlyMockServicesEnabled(Context context, boolean firstMockServiceEnabled, 583 boolean secondMockServiceEnabled) throws Exception { 584 String enabledServices = Settings.Secure.getString(context.getContentResolver(), 585 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); 586 587 StringBuilder servicesToEnable = new StringBuilder(); 588 if (firstMockServiceEnabled) { 589 servicesToEnable.append(MyFirstMockAccessibilityService.sComponentName).append(":"); 590 } 591 if (secondMockServiceEnabled) { 592 servicesToEnable.append(MySecondMockAccessibilityService.sComponentName).append(":"); 593 } 594 595 if (servicesToEnable.equals(enabledServices)) { 596 return; 597 } 598 599 Settings.Secure.putString(context.getContentResolver(), 600 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, servicesToEnable.toString()); 601 602 // we have enabled the services of interest and need to wait until they 603 // are instantiated and started (if needed) and the system binds to them 604 boolean firstMockServiceOK = false; 605 boolean secondMockServiceOK = false; 606 long start = SystemClock.uptimeMillis(); 607 long pollingInterval = TIMEOUT_START_MOCK_ACCESSIBILITY_SERVICES / 6; 608 609 while (SystemClock.uptimeMillis() - start < TIMEOUT_START_MOCK_ACCESSIBILITY_SERVICES) { 610 firstMockServiceOK = !firstMockServiceEnabled 611 || (MyFirstMockAccessibilityService.sInstance != null 612 && MyFirstMockAccessibilityService.sInstance.isSystemBoundAsClient()); 613 614 secondMockServiceOK = !secondMockServiceEnabled 615 || (MySecondMockAccessibilityService.sInstance != null 616 && MySecondMockAccessibilityService.sInstance.isSystemBoundAsClient()); 617 618 if (firstMockServiceOK && secondMockServiceOK) { 619 return; 620 } 621 622 Thread.sleep(pollingInterval); 623 } 624 625 StringBuilder message = new StringBuilder(); 626 message.append("Mock accessibility services not started or system not bound as a client: "); 627 if (!firstMockServiceOK) { 628 message.append(MyFirstMockAccessibilityService.sComponentName); 629 message.append(" "); 630 } 631 if (!secondMockServiceOK) { 632 message.append(MySecondMockAccessibilityService.sComponentName); 633 } 634 throw new IllegalStateException(message.toString()); 635 } 636 637 /** 638 * Asserts the the mock accessibility service has been successfully verified 639 * (which is it has received the expected method calls with expected 640 * arguments) within the {@link #TIMEOUT_BINDER_CALL}. The verified state is 641 * checked by polling upon small intervals. 642 * 643 * @param service The service to verify. 644 * @throws Exception If the verification has failed with exception after the 645 * {@link #TIMEOUT_BINDER_CALL}. 646 */ 647 private void assertMockServiceVerifiedWithinTimeout(MockAccessibilityService service) 648 throws Exception { 649 Exception lastVerifyException = null; 650 long beginTime = SystemClock.uptimeMillis(); 651 long pollTmeout = TIMEOUT_BINDER_CALL / 5; 652 653 // poll until the timeout has elapsed 654 while (SystemClock.uptimeMillis() - beginTime < TIMEOUT_BINDER_CALL) { 655 // sleep first since immediate call will always fail 656 try { 657 Thread.sleep(pollTmeout); 658 } catch (InterruptedException ie) { 659 /* ignore */ 660 } 661 // poll for verification and if this fails save the exception and 662 // keep polling 663 try { 664 service.verify(); 665 // reset so it does not accept more events 666 service.reset(); 667 return; 668 } catch (Exception e) { 669 lastVerifyException = e; 670 } 671 } 672 673 // reset, we have already failed 674 service.reset(); 675 676 // always not null 677 throw lastVerifyException; 678 } 679 680 /** 681 * This class is the first mock {@link AccessibilityService}. 682 */ 683 public static class MyFirstMockAccessibilityService extends MockAccessibilityService { 684 685 /** 686 * The service {@link ComponentName} flattened as a string. 687 */ 688 static String sComponentName; 689 690 /** 691 * Handle to the service instance. 692 */ 693 static MyFirstMockAccessibilityService sInstance; 694 695 /** 696 * Creates a new instance. 697 */ 698 public MyFirstMockAccessibilityService() { 699 sInstance = this; 700 } 701 } 702 703 /** 704 * This class is the first mock {@link AccessibilityService}. 705 */ 706 public static class MySecondMockAccessibilityService extends MockAccessibilityService { 707 708 /** 709 * The service {@link ComponentName} flattened as a string. 710 */ 711 static String sComponentName; 712 713 /** 714 * Handle to the service instance. 715 */ 716 static MySecondMockAccessibilityService sInstance; 717 718 /** 719 * Creates a new instance. 720 */ 721 public MySecondMockAccessibilityService() { 722 sInstance = this; 723 } 724 } 725} 726