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