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