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