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.accessibilityservice.cts;
18 
19 import android.accessibilityservice.AccessibilityServiceInfo;
20 import android.app.Activity;
21 import android.app.UiAutomation;
22 import android.test.ActivityInstrumentationTestCase2;
23 import android.view.accessibility.AccessibilityEvent;
24 
25 import java.util.concurrent.TimeoutException;
26 
27 /**
28  * Base text case for testing accessibility APIs by instrumenting an Activity.
29  */
30 public abstract class AccessibilityActivityTestCase<T extends Activity>
31         extends ActivityInstrumentationTestCase2<T> {
32     /**
33      * Timeout required for pending Binder calls or event processing to
34      * complete.
35      */
36     public static final long TIMEOUT_ASYNC_PROCESSING = 5000;
37 
38     /**
39      * The timeout since the last accessibility event to consider the device idle.
40      */
41     public static final long TIMEOUT_ACCESSIBILITY_STATE_IDLE = 500;
42 
43     /**
44      * @param activityClass
45      */
AccessibilityActivityTestCase(Class<T> activityClass)46     public AccessibilityActivityTestCase(Class<T> activityClass) {
47         super(activityClass);
48     }
49 
50     @Override
setUp()51     public void setUp() throws Exception {
52         super.setUp();
53 
54         AccessibilityServiceInfo info = getInstrumentation().getUiAutomation().getServiceInfo();
55         info.flags |= AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE;
56         info.flags &= ~AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
57         getInstrumentation().getUiAutomation().setServiceInfo(info);
58 
59         startActivityAndWaitForFirstEvent();
60 
61         waitForIdle();
62     }
63 
64     /**
65      * Waits for the UI do be idle.
66      *
67      * @throws TimeoutException if idle cannot be detected.
68      */
waitForIdle()69     public void waitForIdle() throws TimeoutException {
70         getInstrumentation().getUiAutomation().waitForIdle(
71                 TIMEOUT_ACCESSIBILITY_STATE_IDLE,
72                 TIMEOUT_ASYNC_PROCESSING);
73     }
74 
75     /**
76      * @return The string for a given <code>resId</code>.
77      */
getString(int resId)78     public String getString(int resId) {
79         return getInstrumentation().getContext().getString(resId);
80     }
81 
82     /**
83      * Starts the activity under tests and waits for the first accessibility
84      * event from that activity.
85      */
startActivityAndWaitForFirstEvent()86     private void startActivityAndWaitForFirstEvent() throws Exception {
87         AccessibilityEvent awaitedEvent =
88             getInstrumentation().getUiAutomation().executeAndWaitForEvent(
89                 new Runnable() {
90             @Override
91             public void run() {
92                 getActivity();
93                 getInstrumentation().waitForIdleSync();
94             }
95         },
96                 new UiAutomation.AccessibilityEventFilter() {
97             @Override
98             public boolean accept(AccessibilityEvent event) {
99                 final int eventType = event.getEventType();
100                 // Do not check the package name since an event of this type may
101                 // come concurrently from the app and from the IME (since input
102                 // focus goes to the first focusable) but we dispatch one event
103                 // of each type within a timeout. Hence, sometimes the window
104                 // change event from the IME may override the one from the app.
105                 return (eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
106             }
107         },
108         TIMEOUT_ASYNC_PROCESSING);
109         assertNotNull(awaitedEvent);
110     }
111 }
112