1 /* 2 * Copyright (C) 2014 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 android.app.uiautomation.cts; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertNotNull; 22 import static org.junit.Assert.assertSame; 23 import static org.junit.Assert.assertTrue; 24 import static org.junit.Assert.fail; 25 26 import android.Manifest; 27 import android.accessibilityservice.AccessibilityServiceInfo; 28 import android.app.Activity; 29 import android.app.ActivityManager; 30 import android.app.Instrumentation; 31 import android.app.UiAutomation; 32 import android.content.ContentResolver; 33 import android.content.Context; 34 import android.content.Intent; 35 import android.content.pm.PackageManager; 36 import android.os.Process; 37 import android.os.SystemClock; 38 import android.platform.test.annotations.AppModeFull; 39 import android.platform.test.annotations.Presubmit; 40 import android.provider.Settings; 41 import android.view.FrameStats; 42 import android.view.WindowAnimationFrameStats; 43 import android.view.WindowContentFrameStats; 44 import android.view.accessibility.AccessibilityEvent; 45 import android.view.accessibility.AccessibilityManager; 46 import android.view.accessibility.AccessibilityWindowInfo; 47 import android.widget.ListView; 48 49 import androidx.test.InstrumentationRegistry; 50 import androidx.test.runner.AndroidJUnit4; 51 52 import org.junit.Before; 53 import org.junit.Rule; 54 import org.junit.Test; 55 import org.junit.runner.RunWith; 56 57 import java.util.List; 58 import java.util.concurrent.TimeoutException; 59 60 /** 61 * Tests for the UiAutomation APIs. 62 */ 63 @RunWith(AndroidJUnit4.class) 64 public class UiAutomationTest { 65 private static final long QUIET_TIME_TO_BE_CONSIDERED_IDLE_STATE = 1000;//ms 66 67 private static final long TOTAL_TIME_TO_WAIT_FOR_IDLE_STATE = 1000 * 10;//ms 68 69 // Used to enable/disable accessibility services 70 private static final String COMPONENT_NAME_SEPARATOR = ":"; 71 private static final int TIMEOUT_FOR_SERVICE_ENABLE = 10000; // millis; 10s 72 73 @Rule 74 public final UiAutomationLogRule mLogRule = new UiAutomationLogRule( 75 UiAutomationTest.class.getSimpleName()); 76 77 @Before 78 public void setUp() throws Exception { 79 UiAutomation uiAutomation = getInstrumentation().getUiAutomation(); 80 AccessibilityServiceInfo info = uiAutomation.getServiceInfo(); 81 info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS; 82 uiAutomation.setServiceInfo(info); 83 grantWriteSecureSettingsPermission(uiAutomation); 84 } 85 86 @AppModeFull 87 @Test 88 public void testAdoptAllShellPermissions() { 89 final Context context = getInstrumentation().getContext(); 90 final ActivityManager activityManager = context.getSystemService(ActivityManager.class); 91 final PackageManager packageManager = context.getPackageManager(); 92 93 // Try to access APIs guarded by a platform defined signature permissions 94 try { 95 activityManager.getPackageImportance("foo.bar.baz"); 96 fail("Should not be able to access APIs protected by a permission apps cannot get"); 97 } catch (SecurityException e) { 98 /* expected */ 99 } 100 try { 101 packageManager.grantRuntimePermission(context.getPackageName(), 102 Manifest.permission.CAMERA, Process.myUserHandle()); 103 fail("Should not be able to access APIs protected by a permission apps cannot get"); 104 } catch (SecurityException e) { 105 /* expected */ 106 } 107 108 // Access APIs guarded by a platform defined signature permissions 109 try { 110 getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(); 111 112 // Access APIs guarded by a platform defined signature permission 113 activityManager.getPackageImportance("foo.bar.baz"); 114 115 // Grant ourselves a runtime permission (was granted at install) 116 assertSame(packageManager.checkPermission(Manifest.permission.CAMERA, 117 context.getPackageName()), PackageManager.PERMISSION_DENIED); 118 packageManager.grantRuntimePermission(context.getPackageName(), 119 Manifest.permission.CAMERA, Process.myUserHandle()); 120 } catch (SecurityException e) { 121 fail("Should be able to access APIs protected by a permission apps cannot get"); 122 } finally { 123 getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); 124 } 125 // Make sure the grant worked 126 assertSame(packageManager.checkPermission(Manifest.permission.CAMERA, 127 context.getPackageName()), PackageManager.PERMISSION_GRANTED); 128 129 130 // Try to access APIs guarded by a platform defined signature permissions 131 try { 132 activityManager.getPackageImportance("foo.bar.baz"); 133 fail("Should not be able to access APIs protected by a permission apps cannot get"); 134 } catch (SecurityException e) { 135 /* expected */ 136 } 137 try { 138 packageManager.revokeRuntimePermission(context.getPackageName(), 139 Manifest.permission.CAMERA, Process.myUserHandle()); 140 fail("Should not be able to access APIs protected by a permission apps cannot get"); 141 } catch (SecurityException e) { 142 /* expected */ 143 } 144 } 145 146 @AppModeFull 147 @Test 148 public void testAdoptSomeShellPermissions() { 149 final Context context = getInstrumentation().getContext(); 150 151 // Make sure we don't have any of the permissions 152 assertSame(PackageManager.PERMISSION_DENIED, context.checkSelfPermission( 153 Manifest.permission.BATTERY_STATS)); 154 assertSame(PackageManager.PERMISSION_DENIED, context.checkSelfPermission( 155 Manifest.permission.PACKAGE_USAGE_STATS)); 156 157 try { 158 // Adopt a permission 159 getInstrumentation().getUiAutomation().adoptShellPermissionIdentity( 160 Manifest.permission.BATTERY_STATS); 161 // Check one is granted and the other not 162 assertSame(PackageManager.PERMISSION_GRANTED, context.checkSelfPermission( 163 Manifest.permission.BATTERY_STATS)); 164 assertSame(PackageManager.PERMISSION_DENIED, context.checkSelfPermission( 165 Manifest.permission.PACKAGE_USAGE_STATS)); 166 167 // Adopt all permissions 168 getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(); 169 // Check both permissions are granted 170 assertSame(PackageManager.PERMISSION_GRANTED, context.checkSelfPermission( 171 Manifest.permission.BATTERY_STATS)); 172 assertSame(PackageManager.PERMISSION_GRANTED, context.checkSelfPermission( 173 Manifest.permission.PACKAGE_USAGE_STATS)); 174 175 // Adopt a permission 176 getInstrumentation().getUiAutomation().adoptShellPermissionIdentity( 177 Manifest.permission.PACKAGE_USAGE_STATS); 178 // Check one is granted and the other not 179 assertSame(PackageManager.PERMISSION_DENIED, context.checkSelfPermission( 180 Manifest.permission.BATTERY_STATS)); 181 assertSame(PackageManager.PERMISSION_GRANTED, context.checkSelfPermission( 182 Manifest.permission.PACKAGE_USAGE_STATS)); 183 } finally { 184 getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); 185 } 186 } 187 188 @Test 189 public void testWindowContentFrameStats() throws Exception { 190 Activity activity = null; 191 try { 192 UiAutomation uiAutomation = getInstrumentation().getUiAutomation(); 193 194 // Start an activity. 195 Intent intent = new Intent(getInstrumentation().getContext(), 196 UiAutomationTestFirstActivity.class); 197 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 198 activity = getInstrumentation().startActivitySync(intent); 199 200 // Wait for things to settle. 201 uiAutomation.waitForIdle( 202 QUIET_TIME_TO_BE_CONSIDERED_IDLE_STATE, TOTAL_TIME_TO_WAIT_FOR_IDLE_STATE); 203 204 // Wait for Activity draw finish 205 getInstrumentation().waitForIdleSync(); 206 207 // Find the application window. 208 final int windowId = findAppWindowId(uiAutomation.getWindows()); 209 assertTrue(windowId >= 0); 210 211 // Clear stats to be with a clean slate. 212 assertTrue(uiAutomation.clearWindowContentFrameStats(windowId)); 213 214 // Find the list to scroll around. 215 final ListView listView = (ListView) activity.findViewById(R.id.list_view); 216 217 // Scroll a bit. 218 scrollListView(uiAutomation, listView, listView.getAdapter().getCount() - 1); 219 scrollListView(uiAutomation, listView, 0); 220 221 // Get the frame stats. 222 WindowContentFrameStats stats = uiAutomation.getWindowContentFrameStats(windowId); 223 224 // Check the frame stats... 225 226 // We should have something. 227 assertNotNull(stats); 228 229 // The refresh period is always positive. 230 assertTrue(stats.getRefreshPeriodNano() > 0); 231 232 // There is some frame data. 233 final int frameCount = stats.getFrameCount(); 234 assertTrue(frameCount > 0); 235 236 // The frames are ordered in ascending order. 237 assertWindowContentTimestampsInAscendingOrder(stats); 238 239 // The start and end times are based on first and last frame. 240 assertEquals(stats.getStartTimeNano(), stats.getFramePresentedTimeNano(0)); 241 assertEquals(stats.getEndTimeNano(), stats.getFramePresentedTimeNano(frameCount - 1)); 242 } finally { 243 // Clean up. 244 if (activity != null) { 245 activity.finish(); 246 } 247 } 248 } 249 250 @Test 251 public void testWindowContentFrameStatsNoAnimation() throws Exception { 252 Activity activity = null; 253 try { 254 UiAutomation uiAutomation = getInstrumentation().getUiAutomation(); 255 256 // Start an activity. 257 Intent intent = new Intent(getInstrumentation().getContext(), 258 UiAutomationTestFirstActivity.class); 259 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 260 activity = getInstrumentation().startActivitySync(intent); 261 262 // Wait for things to settle. 263 uiAutomation.waitForIdle( 264 QUIET_TIME_TO_BE_CONSIDERED_IDLE_STATE, TOTAL_TIME_TO_WAIT_FOR_IDLE_STATE); 265 266 // Wait for Activity draw finish 267 getInstrumentation().waitForIdleSync(); 268 269 // Find the application window. 270 final int windowId = findAppWindowId(uiAutomation.getWindows()); 271 assertTrue(windowId >= 0); 272 273 // Clear stats to be with a clean slate. 274 assertTrue(uiAutomation.clearWindowContentFrameStats(windowId)); 275 276 // Get the frame stats. 277 WindowContentFrameStats stats = uiAutomation.getWindowContentFrameStats(windowId); 278 279 // Check the frame stats... 280 281 // We should have something. 282 assertNotNull(stats); 283 284 // The refresh period is always positive. 285 assertTrue(stats.getRefreshPeriodNano() > 0); 286 287 // There is no data. 288 assertTrue(stats.getFrameCount() == 0); 289 290 // The start and end times are undefibed as we have no data. 291 assertEquals(stats.getStartTimeNano(), FrameStats.UNDEFINED_TIME_NANO); 292 assertEquals(stats.getEndTimeNano(), FrameStats.UNDEFINED_TIME_NANO); 293 } finally { 294 // Clean up. 295 if (activity != null) { 296 activity.finish(); 297 } 298 } 299 } 300 301 @Presubmit 302 @Test 303 public void testWindowAnimationFrameStats() throws Exception { 304 Activity firstActivity = null; 305 Activity secondActivity = null; 306 try { 307 UiAutomation uiAutomation = getInstrumentation().getUiAutomation(); 308 309 // Start the frist activity. 310 Intent firstIntent = new Intent(getInstrumentation().getContext(), 311 UiAutomationTestFirstActivity.class); 312 firstIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 313 firstActivity = getInstrumentation().startActivitySync(firstIntent); 314 315 // Wait for things to settle. 316 uiAutomation.waitForIdle( 317 QUIET_TIME_TO_BE_CONSIDERED_IDLE_STATE, TOTAL_TIME_TO_WAIT_FOR_IDLE_STATE); 318 319 // Wait for Activity draw finish 320 getInstrumentation().waitForIdleSync(); 321 322 // Clear the window animation stats to be with a clean slate. 323 uiAutomation.clearWindowAnimationFrameStats(); 324 325 // Start the second activity 326 Intent secondIntent = new Intent(getInstrumentation().getContext(), 327 UiAutomationTestSecondActivity.class); 328 secondIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 329 secondActivity = getInstrumentation().startActivitySync(secondIntent); 330 331 // Wait for things to settle. 332 uiAutomation.waitForIdle( 333 QUIET_TIME_TO_BE_CONSIDERED_IDLE_STATE, TOTAL_TIME_TO_WAIT_FOR_IDLE_STATE); 334 335 // Wait for Activity draw finish 336 getInstrumentation().waitForIdleSync(); 337 338 // Get the frame stats. 339 WindowAnimationFrameStats stats = uiAutomation.getWindowAnimationFrameStats(); 340 341 // Check the frame stats... 342 343 // We should have something. 344 assertNotNull(stats); 345 346 // The refresh presiod is always positive. 347 assertTrue(stats.getRefreshPeriodNano() > 0); 348 349 // There is some frame data. 350 final int frameCount = stats.getFrameCount(); 351 assertTrue(frameCount > 0); 352 353 // The frames are ordered in ascending order. 354 assertWindowAnimationTimestampsInAscendingOrder(stats); 355 356 // The start and end times are based on first and last frame. 357 assertEquals(stats.getStartTimeNano(), stats.getFramePresentedTimeNano(0)); 358 assertEquals(stats.getEndTimeNano(), stats.getFramePresentedTimeNano(frameCount - 1)); 359 } finally { 360 // Clean up. 361 if (firstActivity != null) { 362 firstActivity.finish(); 363 } 364 if (secondActivity != null) { 365 secondActivity.finish(); 366 } 367 } 368 } 369 370 @Test 371 public void testWindowAnimationFrameStatsNoAnimation() throws Exception { 372 UiAutomation uiAutomation = getInstrumentation().getUiAutomation(); 373 374 // Wait for things to settle. 375 uiAutomation.waitForIdle( 376 QUIET_TIME_TO_BE_CONSIDERED_IDLE_STATE, TOTAL_TIME_TO_WAIT_FOR_IDLE_STATE); 377 378 // Clear the window animation stats to be with a clean slate. 379 uiAutomation.clearWindowAnimationFrameStats(); 380 381 // Get the frame stats. 382 WindowAnimationFrameStats stats = uiAutomation.getWindowAnimationFrameStats(); 383 384 // Check the frame stats... 385 386 // We should have something. 387 assertNotNull(stats); 388 389 // The refresh presiod is always positive. 390 assertTrue(stats.getRefreshPeriodNano() > 0); 391 392 // There is no data. 393 assertTrue(stats.getFrameCount() == 0); 394 395 // The start and end times are undefibed as we have no data. 396 assertEquals(stats.getStartTimeNano(), FrameStats.UNDEFINED_TIME_NANO); 397 assertEquals(stats.getEndTimeNano(), FrameStats.UNDEFINED_TIME_NANO); 398 } 399 400 @Presubmit 401 @Test 402 public void testUsingUiAutomationAfterDestroy_shouldThrowException() { 403 UiAutomation uiAutomation = getInstrumentation().getUiAutomation(); 404 uiAutomation.destroy(); 405 try { 406 uiAutomation.getServiceInfo(); 407 fail("Expected exception when using destroyed UiAutomation"); 408 } catch (RuntimeException e) { 409 } 410 } 411 412 @AppModeFull 413 @Test 414 public void testDontSuppressAccessibility_canStartA11yService() throws Exception { 415 turnAccessibilityOff(); 416 try { 417 getInstrumentation() 418 .getUiAutomation(UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES); 419 enableAccessibilityService(); 420 assertTrue(UiAutomationTestA11yService.sConnectedInstance.isConnected()); 421 } finally { 422 turnAccessibilityOff(); 423 } 424 } 425 426 @AppModeFull 427 @Test 428 public void testServiceWithNoFlags_shutsDownA11yService() throws Exception { 429 turnAccessibilityOff(); 430 try { 431 UiAutomation uiAutomation = getInstrumentation() 432 .getUiAutomation(UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES); 433 enableAccessibilityService(); 434 assertTrue(UiAutomationTestA11yService.sConnectedInstance.isConnected()); 435 uiAutomation.destroy(); 436 assertTrue(UiAutomationTestA11yService.sConnectedInstance.isConnected()); 437 getInstrumentation().getUiAutomation(); // Should suppress 438 waitForAccessibilityServiceToUnbind(); 439 } finally { 440 turnAccessibilityOff(); 441 } 442 } 443 444 @AppModeFull 445 @Test 446 public void testServiceSupressingA11yServices_a11yServiceStartsWhenDestroyed() 447 throws Exception { 448 turnAccessibilityOff(); 449 try { 450 UiAutomation uiAutomation = getInstrumentation() 451 .getUiAutomation(UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES); 452 enableAccessibilityService(); 453 uiAutomation.destroy(); 454 UiAutomation suppressingUiAutomation = getInstrumentation().getUiAutomation(); 455 // We verify above that the connection is broken here. Make sure we see a new one 456 // after we destroy it 457 waitForAccessibilityServiceToUnbind(); 458 suppressingUiAutomation.destroy(); 459 waitForAccessibilityServiceToStart(); 460 } finally { 461 turnAccessibilityOff(); 462 } 463 } 464 465 @AppModeFull 466 @Test 467 public void testServiceSupressingA11yServices_a11yServiceStartsWhenFlagsChange() 468 throws Exception { 469 turnAccessibilityOff(); 470 try { 471 getInstrumentation() 472 .getUiAutomation(UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES); 473 enableAccessibilityService(); 474 getInstrumentation().getUiAutomation(); 475 // We verify above that the connection is broken here. Make sure we see a new one 476 // after we change the flags 477 waitForAccessibilityServiceToUnbind(); 478 getInstrumentation() 479 .getUiAutomation(UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES); 480 waitForAccessibilityServiceToStart(); 481 } finally { 482 turnAccessibilityOff(); 483 } 484 } 485 486 private void scrollListView(UiAutomation uiAutomation, final ListView listView, 487 final int position) throws TimeoutException { 488 getInstrumentation().runOnMainSync(new Runnable() { 489 @Override 490 public void run() { 491 listView.smoothScrollToPosition(position); 492 } 493 }); 494 Runnable emptyRunnable = new Runnable() { 495 @Override 496 public void run() { 497 } 498 }; 499 UiAutomation.AccessibilityEventFilter scrollFilter = 500 new UiAutomation.AccessibilityEventFilter() { 501 @Override 502 public boolean accept(AccessibilityEvent accessibilityEvent) { 503 return accessibilityEvent.getEventType() 504 == AccessibilityEvent.TYPE_VIEW_SCROLLED; 505 } 506 }; 507 uiAutomation.executeAndWaitForEvent(emptyRunnable, scrollFilter, 508 TOTAL_TIME_TO_WAIT_FOR_IDLE_STATE); 509 uiAutomation.waitForIdle( 510 QUIET_TIME_TO_BE_CONSIDERED_IDLE_STATE, TOTAL_TIME_TO_WAIT_FOR_IDLE_STATE); 511 } 512 513 private void grantWriteSecureSettingsPermission(UiAutomation uiAutomation) { 514 uiAutomation.grantRuntimePermission(getInstrumentation().getContext().getPackageName(), 515 android.Manifest.permission.WRITE_SECURE_SETTINGS); 516 } 517 518 private void enableAccessibilityService() { 519 Context context = getInstrumentation().getContext(); 520 AccessibilityManager manager = 521 (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE); 522 List<AccessibilityServiceInfo> serviceInfos = 523 manager.getInstalledAccessibilityServiceList(); 524 for (int i = 0; i < serviceInfos.size(); i++) { 525 AccessibilityServiceInfo serviceInfo = serviceInfos.get(i); 526 if (context.getString(R.string.uiautomation_a11y_service_description) 527 .equals(serviceInfo.getDescription())) { 528 ContentResolver cr = context.getContentResolver(); 529 String enabledServices = Settings.Secure.getString(cr, 530 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); 531 Settings.Secure.putString(cr, Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 532 enabledServices + COMPONENT_NAME_SEPARATOR + serviceInfo.getId()); 533 Settings.Secure.putInt(cr, Settings.Secure.ACCESSIBILITY_ENABLED, 1); 534 waitForAccessibilityServiceToStart(); 535 return; 536 } 537 } 538 throw new RuntimeException("Test accessibility service not found"); 539 } 540 541 private void waitForAccessibilityServiceToStart() { 542 long timeoutTimeMillis = SystemClock.uptimeMillis() + TIMEOUT_FOR_SERVICE_ENABLE; 543 while (SystemClock.uptimeMillis() < timeoutTimeMillis) { 544 synchronized(UiAutomationTestA11yService.sWaitObjectForConnectOrUnbind) { 545 if (UiAutomationTestA11yService.sConnectedInstance != null) { 546 return; 547 } 548 try { 549 UiAutomationTestA11yService.sWaitObjectForConnectOrUnbind.wait( 550 timeoutTimeMillis - SystemClock.uptimeMillis()); 551 } catch (InterruptedException e) { 552 // Ignored; loop again 553 } 554 } 555 } 556 throw new RuntimeException("Test accessibility service not starting"); 557 } 558 559 private void waitForAccessibilityServiceToUnbind() { 560 long timeoutTimeMillis = SystemClock.uptimeMillis() + TIMEOUT_FOR_SERVICE_ENABLE; 561 while (SystemClock.uptimeMillis() < timeoutTimeMillis) { 562 synchronized(UiAutomationTestA11yService.sWaitObjectForConnectOrUnbind) { 563 if (UiAutomationTestA11yService.sConnectedInstance == null) { 564 return; 565 } 566 try { 567 UiAutomationTestA11yService.sWaitObjectForConnectOrUnbind.wait( 568 timeoutTimeMillis - SystemClock.uptimeMillis()); 569 } catch (InterruptedException e) { 570 // Ignored; loop again 571 } 572 } 573 } 574 throw new RuntimeException("Test accessibility service doesn't unbind"); 575 } 576 577 private void turnAccessibilityOff() { 578 getInstrumentation().getUiAutomation().destroy(); 579 final Object waitLockForA11yOff = new Object(); 580 Context context = getInstrumentation().getContext(); 581 AccessibilityManager manager = 582 (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE); 583 manager.addAccessibilityStateChangeListener( 584 new AccessibilityManager.AccessibilityStateChangeListener() { 585 @Override 586 public void onAccessibilityStateChanged(boolean b) { 587 synchronized (waitLockForA11yOff) { 588 waitLockForA11yOff.notifyAll(); 589 } 590 } 591 }); 592 ContentResolver cr = context.getContentResolver(); 593 Settings.Secure.putString( 594 cr, Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, null); 595 long timeoutTimeMillis = SystemClock.uptimeMillis() + TIMEOUT_FOR_SERVICE_ENABLE; 596 while (SystemClock.uptimeMillis() < timeoutTimeMillis) { 597 synchronized (waitLockForA11yOff) { 598 if (!manager.isEnabled()) { 599 return; 600 } 601 try { 602 waitLockForA11yOff.wait(timeoutTimeMillis - SystemClock.uptimeMillis()); 603 } catch (InterruptedException e) { 604 // Ignored; loop again 605 } 606 } 607 } 608 throw new RuntimeException("Unable to turn accessibility off"); 609 } 610 611 private void assertWindowContentTimestampsInAscendingOrder(WindowContentFrameStats stats) { 612 long lastExpectedTimeNano = 0; 613 long lastPresentedTimeNano = 0; 614 long lastPreparedTimeNano = 0; 615 616 final int frameCount = stats.getFrameCount(); 617 for (int i = 0; i < frameCount; i++) { 618 final long expectedTimeNano = stats.getFramePostedTimeNano(i); 619 assertTrue(expectedTimeNano >= lastExpectedTimeNano); 620 lastExpectedTimeNano = expectedTimeNano; 621 622 final long presentedTimeNano = stats.getFramePresentedTimeNano(i); 623 if (lastPresentedTimeNano == FrameStats.UNDEFINED_TIME_NANO) { 624 assertTrue(presentedTimeNano == FrameStats.UNDEFINED_TIME_NANO); 625 } else if (presentedTimeNano != FrameStats.UNDEFINED_TIME_NANO) { 626 assertTrue(presentedTimeNano >= lastPresentedTimeNano); 627 } 628 lastPresentedTimeNano = presentedTimeNano; 629 630 final long preparedTimeNano = stats.getFrameReadyTimeNano(i); 631 if (lastPreparedTimeNano == FrameStats.UNDEFINED_TIME_NANO) { 632 assertTrue(preparedTimeNano == FrameStats.UNDEFINED_TIME_NANO); 633 } else if (preparedTimeNano != FrameStats.UNDEFINED_TIME_NANO) { 634 assertTrue(preparedTimeNano >= lastPreparedTimeNano); 635 } 636 lastPreparedTimeNano = preparedTimeNano; 637 } 638 } 639 640 private void assertWindowAnimationTimestampsInAscendingOrder(WindowAnimationFrameStats stats) { 641 long lastPresentedTimeNano = 0; 642 643 final int frameCount = stats.getFrameCount(); 644 for (int i = 0; i < frameCount; i++) { 645 final long presentedTimeNano = stats.getFramePresentedTimeNano(i); 646 if (lastPresentedTimeNano == FrameStats.UNDEFINED_TIME_NANO) { 647 assertTrue(presentedTimeNano == FrameStats.UNDEFINED_TIME_NANO); 648 } else if (presentedTimeNano != FrameStats.UNDEFINED_TIME_NANO) { 649 assertTrue(presentedTimeNano >= lastPresentedTimeNano); 650 } 651 lastPresentedTimeNano = presentedTimeNano; 652 } 653 } 654 655 private int findAppWindowId(List<AccessibilityWindowInfo> windows) { 656 final int windowCount = windows.size(); 657 for (int i = 0; i < windowCount; i++) { 658 AccessibilityWindowInfo window = windows.get(i); 659 if (window.getType() == AccessibilityWindowInfo.TYPE_APPLICATION) { 660 return window.getId(); 661 } 662 } 663 return -1; 664 } 665 666 private Instrumentation getInstrumentation() { 667 return InstrumentationRegistry.getInstrumentation(); 668 } 669 } 670