Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2012 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.view.accessibility.cts;
     18 
     19 import static android.accessibility.cts.common.InstrumentedAccessibilityService.TIMEOUT_SERVICE_ENABLE;
     20 import static android.view.accessibility.cts.ServiceControlUtils.getEnabledServices;
     21 import static android.view.accessibility.cts.ServiceControlUtils.waitForConditionWithServiceStateChange;
     22 
     23 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
     24 
     25 import static org.junit.Assert.assertEquals;
     26 import static org.junit.Assert.assertFalse;
     27 import static org.junit.Assert.assertSame;
     28 import static org.junit.Assert.assertTrue;
     29 import static org.junit.Assert.fail;
     30 
     31 import android.accessibility.cts.common.InstrumentedAccessibilityService;
     32 import android.accessibilityservice.AccessibilityServiceInfo;
     33 import android.app.Instrumentation;
     34 import android.app.Service;
     35 import android.app.UiAutomation;
     36 import android.content.Context;
     37 import android.content.pm.ServiceInfo;
     38 import android.os.Handler;
     39 import android.platform.test.annotations.AppModeFull;
     40 import android.provider.Settings;
     41 import android.text.TextUtils;
     42 import android.view.accessibility.AccessibilityEvent;
     43 import android.view.accessibility.AccessibilityManager;
     44 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
     45 import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener;
     46 
     47 import androidx.test.InstrumentationRegistry;
     48 import androidx.test.runner.AndroidJUnit4;
     49 
     50 import com.android.compatibility.common.util.PollingCheck;
     51 import com.android.compatibility.common.util.SystemUtil;
     52 
     53 import org.junit.After;
     54 import org.junit.Before;
     55 import org.junit.Test;
     56 import org.junit.runner.RunWith;
     57 
     58 import java.io.IOException;
     59 import java.util.List;
     60 import java.util.concurrent.atomic.AtomicBoolean;
     61 
     62 /**
     63  * Class for testing {@link AccessibilityManager}.
     64  */
     65 @RunWith(AndroidJUnit4.class)
     66 public class AccessibilityManagerTest {
     67 
     68     private static final Instrumentation sInstrumentation =
     69             InstrumentationRegistry.getInstrumentation();
     70 
     71     private static final String SPEAKING_ACCESSIBLITY_SERVICE_NAME =
     72         "android.view.accessibility.cts.SpeakingAccessibilityService";
     73 
     74     private static final String VIBRATING_ACCESSIBLITY_SERVICE_NAME =
     75         "android.view.accessibility.cts.VibratingAccessibilityService";
     76 
     77     private static final String MULTIPLE_FEEDBACK_TYPES_ACCESSIBILITY_SERVICE_NAME =
     78         "android.view.accessibility.cts.SpeakingAndVibratingAccessibilityService";
     79 
     80     public static final String ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS =
     81             "accessibility_non_interactive_ui_timeout_ms";
     82 
     83     public static final String ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS =
     84             "accessibility_interactive_ui_timeout_ms";
     85 
     86     private AccessibilityManager mAccessibilityManager;
     87 
     88     private Context mTargetContext;
     89 
     90     private Handler mHandler;
     91 
     92     @Before
     93     public void setUp() throws Exception {
     94         mAccessibilityManager = (AccessibilityManager)
     95                 sInstrumentation.getContext().getSystemService(Service.ACCESSIBILITY_SERVICE);
     96         mTargetContext = sInstrumentation.getTargetContext();
     97         mHandler = new Handler(mTargetContext.getMainLooper());
     98         // In case the test runner started a UiAutomation, destroy it to start with a clean slate.
     99         sInstrumentation.getUiAutomation().destroy();
    100         InstrumentedAccessibilityService.disableAllServices(sInstrumentation);
    101     }
    102 
    103     @After
    104     public void tearDown() throws Exception {
    105         InstrumentedAccessibilityService.disableAllServices(sInstrumentation);
    106     }
    107 
    108     @Test
    109     public void testAddAndRemoveAccessibilityStateChangeListener() throws Exception {
    110         AccessibilityStateChangeListener listener = (state) -> {
    111                 /* do nothing */
    112         };
    113         assertTrue(mAccessibilityManager.addAccessibilityStateChangeListener(listener));
    114         assertTrue(mAccessibilityManager.removeAccessibilityStateChangeListener(listener));
    115         assertFalse(mAccessibilityManager.removeAccessibilityStateChangeListener(listener));
    116     }
    117 
    118     @Test
    119     public void testAddAndRemoveTouchExplorationStateChangeListener() throws Exception {
    120         TouchExplorationStateChangeListener listener = (boolean enabled) -> {
    121             // Do nothing.
    122         };
    123         assertTrue(mAccessibilityManager.addTouchExplorationStateChangeListener(listener));
    124         assertTrue(mAccessibilityManager.removeTouchExplorationStateChangeListener(listener));
    125         assertFalse(mAccessibilityManager.removeTouchExplorationStateChangeListener(listener));
    126     }
    127 
    128     @Test
    129     public void testIsTouchExplorationEnabled() throws Exception {
    130         SpeakingAccessibilityService.enableSelf(sInstrumentation);
    131         VibratingAccessibilityService.enableSelf(sInstrumentation);
    132         new PollingCheck() {
    133             @Override
    134             protected boolean check() {
    135                 return mAccessibilityManager.isTouchExplorationEnabled();
    136             }
    137         }.run();
    138     }
    139 
    140     @Test
    141     public void testGetInstalledAccessibilityServicesList() throws Exception {
    142         List<AccessibilityServiceInfo> installedServices =
    143             mAccessibilityManager.getInstalledAccessibilityServiceList();
    144         assertFalse("There must be at least one installed service.", installedServices.isEmpty());
    145         boolean speakingServiceInstalled = false;
    146         boolean vibratingServiceInstalled = false;
    147         final int serviceCount = installedServices.size();
    148         for (int i = 0; i < serviceCount; i++) {
    149             AccessibilityServiceInfo installedService = installedServices.get(i);
    150             ServiceInfo serviceInfo = installedService.getResolveInfo().serviceInfo;
    151             if (mTargetContext.getPackageName().equals(serviceInfo.packageName)
    152                     && SPEAKING_ACCESSIBLITY_SERVICE_NAME.equals(serviceInfo.name)) {
    153                 speakingServiceInstalled = true;
    154             }
    155             if (mTargetContext.getPackageName().equals(serviceInfo.packageName)
    156                     && VIBRATING_ACCESSIBLITY_SERVICE_NAME.equals(serviceInfo.name)) {
    157                 vibratingServiceInstalled = true;
    158             }
    159         }
    160         assertTrue("The speaking service should be installed.", speakingServiceInstalled);
    161         assertTrue("The vibrating service should be installed.", vibratingServiceInstalled);
    162     }
    163 
    164     @Test
    165     public void testGetEnabledAccessibilityServiceList() throws Exception {
    166         SpeakingAccessibilityService.enableSelf(sInstrumentation);
    167         VibratingAccessibilityService.enableSelf(sInstrumentation);
    168         List<AccessibilityServiceInfo> enabledServices =
    169             mAccessibilityManager.getEnabledAccessibilityServiceList(
    170                     AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
    171         boolean speakingServiceEnabled = false;
    172         boolean vibratingServiceEnabled = false;
    173         final int serviceCount = enabledServices.size();
    174         for (int i = 0; i < serviceCount; i++) {
    175             AccessibilityServiceInfo enabledService = enabledServices.get(i);
    176             ServiceInfo serviceInfo = enabledService.getResolveInfo().serviceInfo;
    177             if (mTargetContext.getPackageName().equals(serviceInfo.packageName)
    178                     && SPEAKING_ACCESSIBLITY_SERVICE_NAME.equals(serviceInfo.name)) {
    179                 speakingServiceEnabled = true;
    180             }
    181             if (mTargetContext.getPackageName().equals(serviceInfo.packageName)
    182                     && VIBRATING_ACCESSIBLITY_SERVICE_NAME.equals(serviceInfo.name)) {
    183                 vibratingServiceEnabled = true;
    184             }
    185         }
    186         assertTrue("The speaking service should be enabled.", speakingServiceEnabled);
    187         assertTrue("The vibrating service should be enabled.", vibratingServiceEnabled);
    188     }
    189 
    190     @Test
    191     public void testGetEnabledAccessibilityServiceListForType() throws Exception {
    192         SpeakingAccessibilityService.enableSelf(sInstrumentation);
    193         VibratingAccessibilityService.enableSelf(sInstrumentation);
    194         List<AccessibilityServiceInfo> enabledServices =
    195             mAccessibilityManager.getEnabledAccessibilityServiceList(
    196                     AccessibilityServiceInfo.FEEDBACK_SPOKEN);
    197         assertSame("There should be only one enabled speaking service.", 1, enabledServices.size());
    198         final int serviceCount = enabledServices.size();
    199         for (int i = 0; i < serviceCount; i++) {
    200             AccessibilityServiceInfo enabledService = enabledServices.get(i);
    201             ServiceInfo serviceInfo = enabledService.getResolveInfo().serviceInfo;
    202             if (mTargetContext.getPackageName().equals(serviceInfo.packageName)
    203                     && SPEAKING_ACCESSIBLITY_SERVICE_NAME.equals(serviceInfo.name)) {
    204                 return;
    205             }
    206         }
    207         fail("The speaking service is not enabled.");
    208     }
    209 
    210     @Test
    211     public void testGetEnabledAccessibilityServiceListForTypes() throws Exception {
    212         SpeakingAccessibilityService.enableSelf(sInstrumentation);
    213         VibratingAccessibilityService.enableSelf(sInstrumentation);
    214         // For this test, also enable a service with multiple feedback types
    215         SpeakingAndVibratingAccessibilityService.enableSelf(sInstrumentation);
    216 
    217         List<AccessibilityServiceInfo> enabledServices =
    218                 mAccessibilityManager.getEnabledAccessibilityServiceList(
    219                         AccessibilityServiceInfo.FEEDBACK_SPOKEN
    220                                 | AccessibilityServiceInfo.FEEDBACK_HAPTIC);
    221         assertSame("There should be 3 enabled accessibility services.", 3, enabledServices.size());
    222         boolean speakingServiceEnabled = false;
    223         boolean vibratingServiceEnabled = false;
    224         boolean multipleFeedbackTypesServiceEnabled = false;
    225         final int serviceCount = enabledServices.size();
    226         for (int i = 0; i < serviceCount; i++) {
    227             AccessibilityServiceInfo enabledService = enabledServices.get(i);
    228             ServiceInfo serviceInfo = enabledService.getResolveInfo().serviceInfo;
    229             if (mTargetContext.getPackageName().equals(serviceInfo.packageName)
    230                     && SPEAKING_ACCESSIBLITY_SERVICE_NAME.equals(serviceInfo.name)) {
    231                 speakingServiceEnabled = true;
    232             }
    233             if (mTargetContext.getPackageName().equals(serviceInfo.packageName)
    234                     && VIBRATING_ACCESSIBLITY_SERVICE_NAME.equals(serviceInfo.name)) {
    235                 vibratingServiceEnabled = true;
    236             }
    237             if (mTargetContext.getPackageName().equals(serviceInfo.packageName)
    238                     && MULTIPLE_FEEDBACK_TYPES_ACCESSIBILITY_SERVICE_NAME.equals(
    239                     serviceInfo.name)) {
    240                 multipleFeedbackTypesServiceEnabled = true;
    241             }
    242         }
    243         assertTrue("The speaking service should be enabled.", speakingServiceEnabled);
    244         assertTrue("The vibrating service should be enabled.", vibratingServiceEnabled);
    245         assertTrue("The multiple feedback types service should be enabled.",
    246                 multipleFeedbackTypesServiceEnabled);
    247     }
    248 
    249     @SuppressWarnings("deprecation")
    250     @Test
    251     public void testGetAccessibilityServiceList() throws Exception {
    252         List<ServiceInfo> services = mAccessibilityManager.getAccessibilityServiceList();
    253         boolean speakingServiceInstalled = false;
    254         boolean vibratingServiceInstalled = false;
    255         final int serviceCount = services.size();
    256         for (int i = 0; i < serviceCount; i++) {
    257             ServiceInfo serviceInfo = services.get(i);
    258             if (mTargetContext.getPackageName().equals(serviceInfo.packageName)
    259                     && SPEAKING_ACCESSIBLITY_SERVICE_NAME.equals(serviceInfo.name)) {
    260                 speakingServiceInstalled = true;
    261             }
    262             if (mTargetContext.getPackageName().equals(serviceInfo.packageName)
    263                     && VIBRATING_ACCESSIBLITY_SERVICE_NAME.equals(serviceInfo.name)) {
    264                 vibratingServiceInstalled = true;
    265             }
    266         }
    267         assertTrue("The speaking service should be installed.", speakingServiceInstalled);
    268         assertTrue("The vibrating service should be installed.", vibratingServiceInstalled);
    269     }
    270 
    271     @Test
    272     public void testInterrupt() throws Exception {
    273         // The APIs are heavily tested in the android.accessibilityservice package.
    274         // This just makes sure the call does not throw an exception.
    275         SpeakingAccessibilityService.enableSelf(sInstrumentation);
    276         VibratingAccessibilityService.enableSelf(sInstrumentation);
    277         waitForAccessibilityEnabled();
    278         mAccessibilityManager.interrupt();
    279     }
    280 
    281     @Test
    282     public void testSendAccessibilityEvent() throws Exception {
    283         // The APIs are heavily tested in the android.accessibilityservice package.
    284         // This just makes sure the call does not throw an exception.
    285         SpeakingAccessibilityService.enableSelf(sInstrumentation);
    286         VibratingAccessibilityService.enableSelf(sInstrumentation);
    287         waitForAccessibilityEnabled();
    288         mAccessibilityManager.sendAccessibilityEvent(AccessibilityEvent.obtain(
    289                 AccessibilityEvent.TYPE_VIEW_CLICKED));
    290     }
    291 
    292     @Test
    293     public void testTouchExplorationListenerNoHandler() throws Exception {
    294         final Object waitObject = new Object();
    295         final AtomicBoolean atomicBoolean = new AtomicBoolean(false);
    296 
    297         TouchExplorationStateChangeListener listener = (boolean b) -> {
    298             synchronized (waitObject) {
    299                 atomicBoolean.set(b);
    300                 waitObject.notifyAll();
    301             }
    302         };
    303         mAccessibilityManager.addTouchExplorationStateChangeListener(listener);
    304         SpeakingAccessibilityService.enableSelf(sInstrumentation);
    305         VibratingAccessibilityService.enableSelf(sInstrumentation);
    306         assertAtomicBooleanBecomes(atomicBoolean, true, waitObject,
    307                 "Touch exploration state listener not called when services enabled");
    308         assertTrue("Listener told that touch exploration is enabled, but manager says disabled",
    309                 mAccessibilityManager.isTouchExplorationEnabled());
    310         InstrumentedAccessibilityService.disableAllServices(sInstrumentation);
    311         assertAtomicBooleanBecomes(atomicBoolean, false, waitObject,
    312                 "Touch exploration state listener not called when services disabled");
    313         assertFalse("Listener told that touch exploration is disabled, but manager says it enabled",
    314                 mAccessibilityManager.isTouchExplorationEnabled());
    315         mAccessibilityManager.removeTouchExplorationStateChangeListener(listener);
    316     }
    317 
    318     @Test
    319     public void testTouchExplorationListenerWithHandler() throws Exception {
    320         final Object waitObject = new Object();
    321         final AtomicBoolean atomicBoolean = new AtomicBoolean(false);
    322 
    323         TouchExplorationStateChangeListener listener = (boolean b) -> {
    324             synchronized (waitObject) {
    325                 atomicBoolean.set(b);
    326                 waitObject.notifyAll();
    327             }
    328         };
    329         mAccessibilityManager.addTouchExplorationStateChangeListener(listener, mHandler);
    330         SpeakingAccessibilityService.enableSelf(sInstrumentation);
    331         VibratingAccessibilityService.enableSelf(sInstrumentation);
    332         assertAtomicBooleanBecomes(atomicBoolean, true, waitObject,
    333                 "Touch exploration state listener not called when services enabled");
    334         assertTrue("Listener told that touch exploration is enabled, but manager says disabled",
    335                 mAccessibilityManager.isTouchExplorationEnabled());
    336         InstrumentedAccessibilityService.disableAllServices(sInstrumentation);
    337         assertAtomicBooleanBecomes(atomicBoolean, false, waitObject,
    338                 "Touch exploration state listener not called when services disabled");
    339         assertFalse("Listener told that touch exploration is disabled, but manager says it enabled",
    340                 mAccessibilityManager.isTouchExplorationEnabled());
    341         mAccessibilityManager.removeTouchExplorationStateChangeListener(listener);
    342     }
    343 
    344     @Test
    345     public void testAccessibilityStateListenerNoHandler() throws Exception {
    346         final Object waitObject = new Object();
    347         final AtomicBoolean atomicBoolean = new AtomicBoolean(false);
    348 
    349         AccessibilityStateChangeListener listener = (boolean b) -> {
    350             synchronized (waitObject) {
    351                 atomicBoolean.set(b);
    352                 waitObject.notifyAll();
    353             }
    354         };
    355         mAccessibilityManager.addAccessibilityStateChangeListener(listener);
    356         SpeakingAndVibratingAccessibilityService.enableSelf(sInstrumentation);
    357         assertAtomicBooleanBecomes(atomicBoolean, true, waitObject,
    358                 "Accessibility state listener not called when services enabled");
    359         assertTrue("Listener told that accessibility is enabled, but manager says disabled",
    360                 mAccessibilityManager.isEnabled());
    361         InstrumentedAccessibilityService.disableAllServices(sInstrumentation);
    362         assertAtomicBooleanBecomes(atomicBoolean, false, waitObject,
    363                 "Accessibility state listener not called when services disabled");
    364         assertFalse("Listener told that accessibility is disabled, but manager says enabled",
    365                 mAccessibilityManager.isEnabled());
    366         mAccessibilityManager.removeAccessibilityStateChangeListener(listener);
    367     }
    368 
    369     @Test
    370     public void testAccessibilityStateListenerWithHandler() throws Exception {
    371         final Object waitObject = new Object();
    372         final AtomicBoolean atomicBoolean = new AtomicBoolean(false);
    373 
    374         AccessibilityStateChangeListener listener = (boolean b) -> {
    375             synchronized (waitObject) {
    376                 atomicBoolean.set(b);
    377                 waitObject.notifyAll();
    378             }
    379         };
    380         mAccessibilityManager.addAccessibilityStateChangeListener(listener, mHandler);
    381         SpeakingAndVibratingAccessibilityService.enableSelf(sInstrumentation);
    382         assertAtomicBooleanBecomes(atomicBoolean, true, waitObject,
    383                 "Accessibility state listener not called when services enabled");
    384         assertTrue("Listener told that accessibility is enabled, but manager says disabled",
    385                 mAccessibilityManager.isEnabled());
    386         InstrumentedAccessibilityService.disableAllServices(sInstrumentation);
    387         assertAtomicBooleanBecomes(atomicBoolean, false, waitObject,
    388                 "Accessibility state listener not called when services disabled");
    389         assertFalse("Listener told that accessibility is disabled, but manager says enabled",
    390                 mAccessibilityManager.isEnabled());
    391         mAccessibilityManager.removeAccessibilityStateChangeListener(listener);
    392     }
    393 
    394     @Test
    395     public void testGetRecommendedTimeoutMillis() throws Exception {
    396         SpeakingAccessibilityService.enableSelf(sInstrumentation);
    397         VibratingAccessibilityService.enableSelf(sInstrumentation);
    398         waitForAccessibilityEnabled();
    399         UiAutomation automan = sInstrumentation.getUiAutomation(
    400                 UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
    401         try {
    402             // SpeakingA11yService interactive/nonInteractive timeout is 6000/1000
    403             // vibratingA11yService interactive/nonInteractive timeout is 5000/2000
    404             turnOffRecommendedUiTimoutSettings(automan);
    405             PollingCheck.waitFor(() -> sameRecommendedTimeout(6000, 2000));
    406             turnOnRecommendedUiTimoutSettings(automan, 7000, 0);
    407             PollingCheck.waitFor(() -> sameRecommendedTimeout(7000, 2000));
    408             turnOnRecommendedUiTimoutSettings(automan, 0, 4000);
    409             PollingCheck.waitFor(() -> sameRecommendedTimeout(6000, 4000));
    410             turnOnRecommendedUiTimoutSettings(automan, 9000, 8000);
    411             PollingCheck.waitFor(() -> sameRecommendedTimeout(9000, 8000));
    412             turnOffRecommendedUiTimoutSettings(automan);
    413             PollingCheck.waitFor(() -> sameRecommendedTimeout(6000, 2000));
    414             assertEquals("Should return original timeout", 3000,
    415                     mAccessibilityManager.getRecommendedTimeoutMillis(3000,
    416                             AccessibilityManager.FLAG_CONTENT_ICONS));
    417             assertEquals("Should return original timeout", 7000,
    418                     mAccessibilityManager.getRecommendedTimeoutMillis(7000,
    419                             AccessibilityManager.FLAG_CONTENT_CONTROLS));
    420         } finally {
    421             automan.destroy();
    422         }
    423     }
    424 
    425     @AppModeFull
    426     @Test
    427     public void performShortcut_withoutPermission_fails() {
    428         UiAutomation uiAutomation = sInstrumentation.getUiAutomation(
    429                 UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
    430 
    431         String originalShortcut = configureShortcut(
    432                 uiAutomation, SpeakingAccessibilityService.COMPONENT_NAME.flattenToString());
    433         try {
    434             mAccessibilityManager.performAccessibilityShortcut();
    435             fail("No security exception thrown when performing shortcut without permission");
    436         } catch (SecurityException e) {
    437             // Expected
    438         } finally {
    439             configureShortcut(uiAutomation, originalShortcut);
    440             uiAutomation.destroy();
    441         }
    442         assertTrue(TextUtils.isEmpty(getEnabledServices(mTargetContext.getContentResolver())));
    443     }
    444 
    445     @AppModeFull
    446     @Test
    447     public void performShortcut_withPermission_succeeds() {
    448         UiAutomation uiAutomation = sInstrumentation.getUiAutomation(
    449                 UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
    450 
    451         String originalShortcut = configureShortcut(
    452                 uiAutomation, SpeakingAccessibilityService.COMPONENT_NAME.flattenToString());
    453         try {
    454             runWithShellPermissionIdentity(uiAutomation,
    455                     () -> mAccessibilityManager.performAccessibilityShortcut());
    456             // Make sure the service starts up
    457             final SpeakingAccessibilityService service =
    458                     SpeakingAccessibilityService.getInstanceForClass(
    459                     SpeakingAccessibilityService.class, TIMEOUT_SERVICE_ENABLE);
    460             assertTrue("Speaking accessibility service starts up", service != null);
    461         } finally {
    462             configureShortcut(uiAutomation, originalShortcut);
    463             uiAutomation.destroy();
    464         }
    465     }
    466 
    467     private String configureShortcut(UiAutomation uiAutomation, String shortcutService) {
    468         String currentService = Settings.Secure.getString(mTargetContext.getContentResolver(),
    469                 Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE);
    470         putSecureSetting(uiAutomation, Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
    471                 shortcutService);
    472         if (shortcutService != null) {
    473             runWithShellPermissionIdentity(uiAutomation, () ->
    474                     waitForConditionWithServiceStateChange(mTargetContext, () -> TextUtils.equals(
    475                             mAccessibilityManager.getAccessibilityShortcutService(),
    476                             shortcutService),
    477                             TIMEOUT_SERVICE_ENABLE,
    478                             "accessibility shortcut set to test service"));
    479         }
    480         return currentService;
    481     }
    482 
    483     private void assertAtomicBooleanBecomes(AtomicBoolean atomicBoolean,
    484             boolean expectedValue, Object waitObject, String message)
    485             throws Exception {
    486         long timeoutTime =
    487                 System.currentTimeMillis() + TIMEOUT_SERVICE_ENABLE;
    488         synchronized (waitObject) {
    489             while ((atomicBoolean.get() != expectedValue)
    490                     && (System.currentTimeMillis() < timeoutTime)) {
    491                 waitObject.wait(timeoutTime - System.currentTimeMillis());
    492             }
    493         }
    494         assertTrue(message, atomicBoolean.get() == expectedValue);
    495     }
    496 
    497     private void waitForAccessibilityEnabled() throws InterruptedException {
    498         final Object waitObject = new Object();
    499 
    500         AccessibilityStateChangeListener listener = (boolean b) -> {
    501             synchronized (waitObject) {
    502                 waitObject.notifyAll();
    503             }
    504         };
    505         mAccessibilityManager.addAccessibilityStateChangeListener(listener);
    506         long timeoutTime =
    507                 System.currentTimeMillis() + TIMEOUT_SERVICE_ENABLE;
    508         synchronized (waitObject) {
    509             while (!mAccessibilityManager.isEnabled()
    510                     && (System.currentTimeMillis() < timeoutTime)) {
    511                 waitObject.wait(timeoutTime - System.currentTimeMillis());
    512             }
    513         }
    514         mAccessibilityManager.removeAccessibilityStateChangeListener(listener);
    515         assertTrue("Timed out enabling accessibility", mAccessibilityManager.isEnabled());
    516     }
    517 
    518     private void turnOffRecommendedUiTimoutSettings(UiAutomation automan) {
    519         putSecureSetting(automan, ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS, null);
    520         putSecureSetting(automan, ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS, null);
    521     }
    522 
    523     private void turnOnRecommendedUiTimoutSettings(UiAutomation automan,
    524             int interactiveUiTimeout, int nonInteractiveUiTimeout) {
    525         putSecureSetting(automan, ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS,
    526                 Integer.toString(interactiveUiTimeout));
    527         putSecureSetting(automan, ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS,
    528                 Integer.toString(nonInteractiveUiTimeout));
    529     }
    530 
    531     private boolean sameRecommendedTimeout(int interactiveUiTimeout,
    532             int nonInteractiveUiTimeout) {
    533         final int currentInteractiveUiTimeout = mAccessibilityManager
    534                 .getRecommendedTimeoutMillis(0, AccessibilityManager.FLAG_CONTENT_CONTROLS);
    535         final int currentNonInteractiveUiTimeout = mAccessibilityManager
    536                 .getRecommendedTimeoutMillis(0, AccessibilityManager.FLAG_CONTENT_ICONS);
    537         return (currentInteractiveUiTimeout == interactiveUiTimeout
    538                 && currentNonInteractiveUiTimeout == nonInteractiveUiTimeout);
    539     }
    540 
    541     private void putSecureSetting(UiAutomation automan, String name, String value) {
    542         final StringBuilder cmd = new StringBuilder("settings put secure ")
    543                 .append(name).append(" ")
    544                 .append(value);
    545         try {
    546             SystemUtil.runShellCommand(automan, cmd.toString());
    547         } catch (IOException e) {
    548             fail("Fail to run shell command");
    549         }
    550     }
    551 }
    552