1 /* 2 * Copyright (C) 2021 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.translation.cts; 18 19 import static com.android.compatibility.common.util.ShellUtils.runShellCommand; 20 21 import android.app.Instrumentation; 22 import android.app.UiAutomation; 23 import android.content.ContentCaptureOptions; 24 import android.content.Context; 25 import android.graphics.Bitmap; 26 import android.os.UserHandle; 27 import android.util.Log; 28 29 import androidx.test.InstrumentationRegistry; 30 import androidx.test.uiautomator.By; 31 import androidx.test.uiautomator.UiDevice; 32 import androidx.test.uiautomator.UiObject2; 33 import androidx.test.uiautomator.Until; 34 35 import com.android.compatibility.common.util.BitmapUtils; 36 37 import java.io.File; 38 import java.io.IOException; 39 40 /** 41 * Helper for common funcionalities. 42 */ 43 public final class Helper { 44 45 private static final String TAG = "Helper"; 46 47 public static final String ACTIVITY_PACKAGE = "android.translation.cts"; 48 49 public static final String ACTION_REGISTER_UI_TRANSLATION_CALLBACK = 50 "android.translation.cts.action.REGISTER_UI_TRANSLATION_CALLBACK"; 51 public static final String ACTION_UNREGISTER_UI_TRANSLATION_CALLBACK = 52 "android.translation.cts.action.UNREGISTER_UI_TRANSLATION_CALLBACK"; 53 public static final String ACTION_ASSERT_UI_TRANSLATION_CALLBACK_ON_START = 54 "android.translation.cts.action.ASSERT_UI_TRANSLATION_CALLBACK_ON_START"; 55 public static final String ACTION_ASSERT_UI_TRANSLATION_CALLBACK_ON_FINISH = 56 "android.translation.cts.action.ASSERT_UI_TRANSLATION_CALLBACK_ON_FINISH"; 57 public static final String ACTION_ASSERT_UI_TRANSLATION_CALLBACK_ON_RESUME = 58 "android.translation.cts.action.ASSERT_UI_TRANSLATION_CALLBACK_ON_RESUME"; 59 public static final String ACTION_ASSERT_UI_TRANSLATION_CALLBACK_ON_PAUSE = 60 "android.translation.cts.action.ASSERT_UI_TRANSLATION_CALLBACK_ON_PAUSE"; 61 62 public static final String EXTRA_FINISH_COMMAND = "finish_command"; 63 public static final String EXTRA_SOURCE_LOCALE = "source_locale"; 64 public static final String EXTRA_TARGET_LOCALE = "target_locale"; 65 public static final String EXTRA_PACKAGE_NAME = "package_name"; 66 public static final String EXTRA_CALL_COUNT = "call_count"; 67 68 public static final int COMMAND_CREATE_TRANSLATOR = 1; 69 70 public static final String CUSTOM_TRANSLATION_ID_MY_TAG = "myTag"; 71 public static final String LOCAL_TEST_FILES_DIR = "/sdcard/CtsTranslationTestCases"; 72 public static final int TEMP_SERVICE_DURATION_MS = 30_000; 73 74 private static final String LOG_TAG = "log.tag.UiTranslation"; 75 76 /** 77 * Sets the translation service temporarily. 78 * 79 * @param service name of temporary translation service. 80 */ setTemporaryTranslationService(String service)81 public static void setTemporaryTranslationService(String service) { 82 Log.d(TAG, "Setting translation service to " + service); 83 final int userId = UserHandle.myUserId(); 84 runShellCommand("cmd translation set temporary-service %d %s %d", userId, service, 85 TEMP_SERVICE_DURATION_MS); 86 } 87 88 /** 89 * Resets the translation service. 90 */ resetTemporaryTranslationService()91 public static void resetTemporaryTranslationService() { 92 final int userId = UserHandle.myUserId(); 93 Log.d(TAG, "Resetting back user " + userId + " to default translation service"); 94 runShellCommand("cmd translation set temporary-service %d", userId); 95 } 96 97 /** 98 * Sets the content capture service temporarily. 99 * 100 * @param service name of temporary translation service. 101 */ setTemporaryContentCaptureService(String service)102 public static void setTemporaryContentCaptureService(String service) { 103 Log.d(TAG, "Setting content capture service to " + service); 104 final int userId = UserHandle.myUserId(); 105 runShellCommand("cmd content_capture set temporary-service %d %s %d", userId, service, 106 TEMP_SERVICE_DURATION_MS); 107 } 108 109 /** 110 * Resets the content capture service. 111 */ resetTemporaryContentCaptureService()112 public static void resetTemporaryContentCaptureService() { 113 final int userId = UserHandle.myUserId(); 114 Log.d(TAG, "Resetting back user " + userId + " to default service"); 115 runShellCommand("cmd content_capture set temporary-service %d", userId); 116 } 117 118 /** 119 * Enable or disable the default content capture service. 120 * 121 * @param enabled {@code true} to enable default content capture service. 122 */ setDefaultContentCaptureServiceEnabled(boolean enabled)123 public static void setDefaultContentCaptureServiceEnabled(boolean enabled) { 124 final int userId = UserHandle.myUserId(); 125 Log.d(TAG, "setDefaultServiceEnabled(user=" + userId + ", enabled= " + enabled + ")"); 126 runShellCommand("cmd content_capture set default-service-enabled %d %s", userId, 127 Boolean.toString(enabled)); 128 } 129 130 /** 131 * Add the cts itself into content capture allow list. 132 * 133 * @param context Context of the app. 134 */ allowSelfForContentCapture(Context context)135 public static void allowSelfForContentCapture(Context context) { 136 final ContentCaptureOptions options = ContentCaptureOptions.forWhitelistingItself(); 137 Log.v(TAG, "allowSelfForContentCapture(): options=" + options); 138 context.getApplicationContext().setContentCaptureOptions(options); 139 } 140 141 /** 142 * Reset the cts itself from content capture allow list. 143 * 144 * @param context Context of the app. 145 */ unAllowSelfForContentCapture(Context context)146 public static void unAllowSelfForContentCapture(Context context) { 147 Log.v(TAG, "unAllowSelfForContentCapture()"); 148 context.getApplicationContext().setContentCaptureOptions(null); 149 } 150 151 /** 152 * Return a ui object for resource id. 153 * 154 * @param resourcePackage package of the object 155 * @param resourceId the resource id of the object 156 */ findObjectByResId(String resourcePackage, String resourceId)157 public static UiObject2 findObjectByResId(String resourcePackage, String resourceId) { 158 final UiDevice uiDevice = 159 UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); 160 final UiObject2 foundObj = uiDevice.wait( 161 Until.findObject(By.res(resourcePackage, resourceId)), 5_000L); 162 return foundObj; 163 } 164 165 /** 166 * Enable DEBUG log and returns the original log level value. 167 */ enableDebugLog()168 public static String enableDebugLog() { 169 String originalValue = System.getProperty(LOG_TAG, ""); 170 System.setProperty(LOG_TAG, "DEBUG"); 171 Log.d(TAG, "enableDebugLog(), original value = " + originalValue); 172 return originalValue; 173 } 174 175 /** 176 * Disable debug log. 177 * 178 * @param level the log level. The value can be DEBUG, INFO, VERBOSE or empty if not set. 179 */ disableDebugLog(String level)180 public static void disableDebugLog(String level) { 181 Log.d(TAG, "disableDebugLog(), set level " + level); 182 System.setProperty(LOG_TAG, level); 183 } 184 185 // TODO: Move to a library that can be shared for smart os components. 186 /** 187 * Takes a screenshot and save it in the file system for analysis. 188 */ takeScreenshotAndSave(Context context, String testName, String targetFolder)189 public static void takeScreenshotAndSave(Context context, String testName, 190 String targetFolder) { 191 File file = null; 192 try { 193 file = createTestFile(testName,"sreenshot.png", targetFolder); 194 if (file != null) { 195 Log.i(TAG, "Taking screenshot on " + file); 196 final Bitmap screenshot = takeScreenshot(); 197 saveBitmapToFile(screenshot, file); 198 } 199 } catch (Exception e) { 200 Log.e(TAG, "Error taking screenshot and saving on " + file, e); 201 } 202 } 203 saveBitmapToFile(Bitmap bitmap, File file)204 public static File saveBitmapToFile(Bitmap bitmap, File file) { 205 Log.i(TAG, "Saving bitmap at " + file); 206 BitmapUtils.saveBitmap(bitmap, file.getParent(), file.getName()); 207 return file; 208 } 209 takeScreenshot()210 private static Bitmap takeScreenshot() { 211 final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); 212 UiAutomation automan = instrumentation.getUiAutomation(); 213 final Bitmap bitmap = automan.takeScreenshot(); 214 return bitmap; 215 } 216 createTestFile(String testName, String name, String targetFolder)217 public static File createTestFile(String testName, String name, String targetFolder) 218 throws IOException { 219 final File dir = getLocalDirectory(targetFolder); 220 if (dir == null) return null; 221 final String prefix = testName.replaceAll("\\.|\\(|\\/", "_").replaceAll("\\)", ""); 222 final String filename = prefix + "-" + name; 223 224 return createFile(dir, filename); 225 } 226 getLocalDirectory(String targetFolder)227 private static File getLocalDirectory(String targetFolder) { 228 final File dir = new File(targetFolder); 229 dir.mkdirs(); 230 if (!dir.exists()) { 231 Log.e(TAG, "Could not create directory " + dir); 232 return null; 233 } 234 return dir; 235 } 236 createFile(File dir, String filename)237 private static File createFile(File dir, String filename) throws IOException { 238 final File file = new File(dir, filename); 239 if (file.exists()) { 240 Log.v(TAG, "Deleting file " + file); 241 file.delete(); 242 } 243 if (!file.createNewFile()) { 244 Log.e(TAG, "Could not create file " + file); 245 return null; 246 } 247 return file; 248 } 249 } 250