1 /*
2  * Copyright (C) 2018 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 package android.contentcaptureservice.cts;
17 
18 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
19 
20 import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
21 
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.res.Resources;
25 import android.os.SystemClock;
26 import android.os.UserHandle;
27 import android.util.ArraySet;
28 import android.util.Log;
29 import android.view.View;
30 import android.view.contentcapture.ContentCaptureSession;
31 import android.widget.TextView;
32 
33 import androidx.annotation.NonNull;
34 import androidx.annotation.Nullable;
35 
36 import com.android.compatibility.common.util.Timeout;
37 import com.android.compatibility.common.util.UserSettings;
38 
39 import java.io.File;
40 import java.io.IOException;
41 import java.nio.file.Files;
42 import java.nio.file.Paths;
43 import java.util.Set;
44 import java.util.concurrent.Callable;
45 import java.util.concurrent.CountDownLatch;
46 import java.util.concurrent.TimeUnit;
47 
48 /**
49  * Helper for common funcionalities.
50  */
51 public final class Helper {
52 
53     public static final String TAG = "ContentCaptureTest";
54 
55     public static final long GENERIC_TIMEOUT_MS = 10_000;
56 
57     public static final String MY_PACKAGE = "android.contentcaptureservice.cts";
58     public static final String MY_SECOND_PACKAGE = "android.contentcaptureservice.cts2";
59     public static final String OTHER_PACKAGE = "NOT.android.contentcaptureservice.cts";
60 
61     public static final String EXTRA_VERIFY_RESULT = "verify_result";
62 
63     public static final Set<String> NO_PACKAGES = null;
64     public static final Set<ComponentName> NO_ACTIVITIES = null;
65 
66     public static final long MY_EPOCH = SystemClock.uptimeMillis();
67 
68     public static final String RESOURCE_STRING_SERVICE_NAME = "config_defaultContentCaptureService";
69 
70     public static final Context sContext = getInstrumentation().getTargetContext();
71     public static final UserSettings sUserSettings = new UserSettings(sContext);
72 
73     private static final Timeout MY_TIMEOUT = new Timeout("MY_TIMEOUT", GENERIC_TIMEOUT_MS, 2F,
74             GENERIC_TIMEOUT_MS);
75 
76     /**
77      * Awaits for a latch to be counted down.
78      */
await(@onNull CountDownLatch latch, @NonNull String fmt, @Nullable Object... args)79     public static void await(@NonNull CountDownLatch latch, @NonNull String fmt,
80             @Nullable Object... args)
81             throws InterruptedException {
82         final boolean called = latch.await(GENERIC_TIMEOUT_MS, TimeUnit.MILLISECONDS);
83         if (!called) {
84             throw new IllegalStateException(String.format(fmt, args)
85                     + " in " + GENERIC_TIMEOUT_MS + "ms");
86         }
87     }
88 
89     /**
90      * Sets the content capture service.
91      */
setService(@onNull String service)92     public static void setService(@NonNull String service) {
93         final int userId = getCurrentUserId();
94         Log.d(TAG, "Setting service for user " + userId + " to " + service);
95         // TODO(b/123540602): use @TestingAPI to get max duration constant
96         runShellCommand("cmd content_capture set temporary-service %d %s 30000", userId, service);
97     }
98 
99     /**
100      * Resets the content capture service.
101      */
resetService()102     public static void resetService() {
103         final int userId = getCurrentUserId();
104         Log.d(TAG, "Resetting back user " + userId + " to default service");
105         runShellCommand("cmd content_capture set temporary-service %d", userId);
106     }
107 
108     /**
109      * Enables / disables the default service.
110      */
setDefaultServiceEnabled(boolean enabled)111     public static void setDefaultServiceEnabled(boolean enabled) {
112         final int userId = getCurrentUserId();
113         Log.d(TAG, "setDefaultServiceEnabled(user=" + userId + ", enabled= " + enabled + ")");
114         runShellCommand("cmd content_capture set default-service-enabled %d %s", userId,
115                 Boolean.toString(enabled));
116     }
117 
118     /**
119      * Gets the component name for a given class.
120      */
componentNameFor(@onNull Class<?> clazz)121     public static ComponentName componentNameFor(@NonNull Class<?> clazz) {
122         return new ComponentName(MY_PACKAGE, clazz.getName());
123     }
124 
125     /**
126      * Creates a view that can be added to a parent and is important for content capture
127      */
newImportantView(@onNull Context context, @NonNull String text)128     public static TextView newImportantView(@NonNull Context context, @NonNull String text) {
129         final TextView child = new TextView(context);
130         child.setText(text);
131         child.setImportantForContentCapture(View.IMPORTANT_FOR_CONTENT_CAPTURE_YES);
132         Log.v(TAG, "newImportantView(text=" + text + ", id=" + child.getAutofillId() + ")");
133         return child;
134     }
135 
136     /**
137      * Creates a view that can be added to a parent and is important for content capture
138      */
newImportantView(@onNull Context context, @NonNull ContentCaptureSession session, @NonNull String text)139     public static TextView newImportantView(@NonNull Context context,
140             @NonNull ContentCaptureSession session, @NonNull String text) {
141         final TextView child = newImportantView(context, text);
142         child.setContentCaptureSession(session);
143         return child;
144     }
145 
146     /**
147      * Gets a string from the Android resources.
148      */
getInternalString(@onNull String id)149     public static String getInternalString(@NonNull String id) {
150         final Resources resources = sContext.getResources();
151         final int stringId = resources.getIdentifier(id, "string", "android");
152         return resources.getString(stringId);
153     }
154 
155     /**
156      * Runs an {@code assertion}, retrying until {@link #MY_TIMEOUT} is reached.
157      */
eventually(@onNull String description, @NonNull Callable<T> assertion)158     public static <T> T eventually(@NonNull String description, @NonNull Callable<T> assertion)
159             throws Exception {
160         return MY_TIMEOUT.run(description, assertion);
161     }
162 
163     /**
164      * Creates a Set with the given objects.
165      */
toSet(@uppressWarnings"unchecked") @ullable T... objs)166     public static <T> ArraySet<T> toSet(@SuppressWarnings("unchecked") @Nullable T... objs) {
167         final ArraySet<T> set = new ArraySet<>();
168         if (objs != null) {
169             for (int i = 0; i < objs.length; i++) {
170                 final T t = objs[i];
171                 set.add(t);
172             }
173         }
174         return set;
175     }
176 
177     /**
178      * Gets the content of the given file.
179      */
read(@onNull File file)180     public static String read(@NonNull File file) throws IOException {
181         Log.d(TAG, "Reading " + file);
182         final byte[] bytes = Files.readAllBytes(Paths.get(file.getAbsolutePath()));
183         return bytes == null ? null : new String(bytes);
184     }
185 
getCurrentUserId()186     private static int getCurrentUserId() {
187         return UserHandle.myUserId();
188     }
189 
Helper()190     private Helper() {
191         throw new UnsupportedOperationException("contain static methods only");
192     }
193 }
194