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