1 /*
2  * Copyright (C) 2017 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.inputmethodservice.cts.devicetest;
18 
19 import static android.inputmethodservice.cts.DeviceEvent.isFrom;
20 import static android.inputmethodservice.cts.DeviceEvent.isType;
21 import static android.inputmethodservice.cts.common.DeviceEventConstants.DeviceEventType.TEST_START;
22 
23 import android.content.ContentResolver;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.database.Cursor;
27 import android.inputmethodservice.cts.DeviceEvent;
28 import android.inputmethodservice.cts.common.DeviceEventConstants.DeviceEventType;
29 import android.inputmethodservice.cts.common.EventProviderConstants.EventTableConstants;
30 import android.inputmethodservice.cts.common.test.TestInfo;
31 import android.net.Uri;
32 import androidx.annotation.IdRes;
33 import android.support.test.InstrumentationRegistry;
34 import android.support.test.uiautomator.By;
35 import android.support.test.uiautomator.UiDevice;
36 import android.support.test.uiautomator.UiObject2;
37 import android.support.test.uiautomator.Until;
38 
39 import java.io.IOException;
40 import java.util.concurrent.TimeUnit;
41 import java.util.function.Predicate;
42 import java.util.stream.Stream;
43 
44 /**
45  * Helper object for device side test.
46  */
47 final class TestHelper {
48 
49     /** Content URI of device event provider. */
50     private static final Uri DEVICE_EVENTS_CONTENT_URI = Uri.parse(EventTableConstants.CONTENT_URI);
51     private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(5);
52 
53     private final TestInfo mTestInfo;
54     private final ContentResolver mResolver;
55     private final Context mTargetContext;
56     private final UiDevice mUiDevice;
57 
58     /**
59      * Construct a helper object of specified test method.
60      *
61      * @param testClass a {@link Class} of test.
62      * @param testMethod a name of test method.
63      */
TestHelper(final Class<?> testClass, final String testMethod)64     TestHelper(final Class<?> testClass, final String testMethod) {
65         final Context testContext = InstrumentationRegistry.getContext();
66         mTestInfo = new TestInfo(testContext.getPackageName(), testClass.getName(), testMethod);
67         mResolver = testContext.getContentResolver();
68         mTargetContext = InstrumentationRegistry.getTargetContext();
69         mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
70     }
71 
72     /**
73      * Execute a shell {@code command} and return its standard out.
74      * @param command a shell command text to execute.
75      * @return command's standard output without ending newline.
76      * @throws IOException
77      */
shell(final String command)78     String shell(final String command) throws IOException {
79         return mUiDevice.executeShellCommand(command).trim();
80     }
81 
82     /**
83      * Launching an Activity for test, and wait for completions of launch.
84      * @param packageName activity's app package name.
85      * @param className activity's class name.
86      * @param uri uri to be handled.
87      */
launchActivity(final String packageName, final String className, final String uri)88     void launchActivity(final String packageName, final String className, final String uri) {
89         final Intent intent = new Intent()
90                 .setAction(Intent.ACTION_VIEW)
91                 .addCategory(Intent.CATEGORY_BROWSABLE)
92                 .addCategory(Intent.CATEGORY_DEFAULT)
93                 .setData(Uri.parse(uri))
94                 .setClassName(packageName, className)
95                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
96                 .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
97         InstrumentationRegistry.getContext().startActivity(intent);
98         mUiDevice.wait(Until.hasObject(By.pkg(packageName).depth(0)), TIMEOUT);
99     }
100 
101     /**
102      * Find an UI element from resource ID.
103      * @param resourceName name of finding UI element.
104      * @return {@link UiObject2} of found UI element.
105      */
findUiObject(String resourceName)106     UiObject2 findUiObject(String resourceName) {
107         return mUiDevice.findObject(By.res(resourceName));
108     }
109 
110     /**
111      * Return all device events as {@link Stream}
112      * @return {@link Stream<DeviceEvent>} of all device events.
113      */
queryAllEvents()114     Stream<DeviceEvent> queryAllEvents() {
115         try (final Cursor cursor = mResolver.query(
116                 DEVICE_EVENTS_CONTENT_URI,
117                 null /* projection */,
118                 null /* selection */,
119                 null /* selectionArgs */,
120                 null /* sortOrder */)) {
121             return DeviceEvent.buildStream(cursor);
122         }
123     }
124 
125     /**
126      * Build a {@link Predicate} can be used for skipping device events in {@link Stream} until
127      * {@link DeviceEventType#TEST_START TEST_START} device event of this test method.
128      * @return {@llink Predicate<DeviceEvent>} that return true after accepting
129      *         {@link DeviceEventType#TEST_START TEST_START} of this test method.
130      */
isStartOfTest()131     Predicate<DeviceEvent> isStartOfTest() {
132         return isFrom(mTestInfo.getTestName()).and(isType(TEST_START));
133     }
134 }
135