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