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