gpt4 book ai didi

java - 编写自定义 Android ViewAction 以截取屏幕截图

转载 作者:行者123 更新时间:2023-11-28 20:41:58 26 4
gpt4 key购买 nike

我想在使用 espresso 在 Android 中执行操作之前截取屏幕截图。

protected T performAction(ViewAction viewAction) {
ViewAction screenShotAction = new ScreenShotAction();
viewInteraction.perform(screenShotAction);
viewInteraction.perform(viewAction);
return returnGeneric();
}

例如,如果在我的测试中我执行了 click(),那么我会在执行 click() 之前截取设备的屏幕截图。

这是在 ScreenShotAction 类中获取屏幕截图的代码

@Override
public void perform(UiController uiController, View view) {

View rootView = view.getRootView();
String state = Environment.getExternalStorageState();
if(Environment.MEDIA_MOUNTED.equals(state)) {
File picDir = new File(Environment.getExternalStorageDirectory() + "app_" + "test");

if (!picDir.exists()) {
picDir.mkdir();
}

rootView.setDrawingCacheEnabled(true);
rootView.buildDrawingCache(true);
Bitmap bitmap = rootView.getDrawingCache();
String fileName = "test.jpg";
File picFile = new File(picDir + "/" + fileName);

try {
picFile.createNewFile();
FileOutputStream picOut = new FileOutputStream(picFile);
bitmap = Bitmap.createBitmap(rootView.getWidth(), rootView.getHeight(), Bitmap.Config.ARGB_8888);
boolean saved = bitmap.compress(Bitmap.CompressFormat.JPEG, 100, picOut);

if (saved) {
// good
} else {
// error
throw new Exception("Image not saved");
}

picOut.flush();
picOut.close();

} catch (Exception e) {
e.printStackTrace();
}
rootView.destroyDrawingCache();
}
}

我在手机的图片目录或任何其他目录中没有看到任何图像文件。我相信屏幕截图方法是可靠的,但不确定我是否正确调用了该方法。

viewInteraction.perform(screenShotAction) 是调用我的自定义 View 操作的正确方式吗?

请提前帮助并谢谢你。

最佳答案

您可以执行以下操作:

public class CaptureImage {
@SuppressWarnings("unused")
private static final String TAG = CaptureImage.class.getSimpleName();
private static final String NAME_SEPARATOR = "_";
private static final String EXTENSION = ".png";
private static final Object LOCK = new Object();
private static boolean outputNeedsClear = true;
private static final Pattern NAME_VALIDATION = Pattern.compile("[a-zA-Z0-9_-]+");

public static void takeScreenshot(View currentView, String className,
String methodName, @Nullable String prefix) {
methodName = methodName.replaceAll("[\\[\\](){}]", "");
if (!NAME_VALIDATION.matcher(methodName).matches()) {
throw new IllegalArgumentException(
"Name must match " + NAME_VALIDATION.pattern() +
" and " + methodName + " was received.");
}
Context context = InstrumentationRegistry.getTargetContext();
MyRunnable myRunnable = new MyRunnable(context, currentView, className, methodName, prefix);
Activity activity =
((Application)context.getApplicationContext()).getCurrentActivity();
activity.runOnUiThread(myRunnable);
}

private static class MyRunnable implements Runnable {
private View mView;
private Context mContext;
private String mClassName;
private String mMethodName;
private String mPrefix;

MyRunnable(Context context, View view, String className, String methodName, String prefix) {
mContext = context;
mView = view;
mClassName = className;
mMethodName = methodName;
mPrefix = prefix;
}

@TargetApi(VERSION_CODES.JELLY_BEAN_MR2)
public void run() {
UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
if (uiAutomation == null) {
return;
}
OutputStream out = null;
Bitmap bitmap = null;
try {
String timestamp = new SimpleDateFormat("MM_dd_HH_mm_ss", Locale.ENGLISH)
.format(new Date());
File screenshotDirectory = getScreenshotFolder();
int statusBarHeight = getStatusBarHeightOnDevice();
bitmap = uiAutomation.takeScreenshot();
Bitmap screenshot = Bitmap.createBitmap(bitmap, 0, statusBarHeight,
mView.getWidth(), mView.getHeight() - statusBarHeight);
String screenshotName = mMethodName + NAME_SEPARATOR +
(mPrefix != null ? (mPrefix + NAME_SEPARATOR) : "") +
timestamp + EXTENSION;
Log.d("YOUR_TAG", "Screenshot name: " + screenshotName);
File imageFile = new File(screenshotDirectory, screenshotName);
out = new FileOutputStream(imageFile);
screenshot.compress(Bitmap.CompressFormat.PNG, 90, out);
out.flush();
} catch (Throwable t) {
Log.e("YOUR_LOG", "Unable to capture screenshot.", t);
} finally {
try {
if (out != null) {
out.close();
}
} catch (Exception ignored) {
}
if (bitmap != null) {
bitmap.recycle();
}
}
}

private int getStatusBarHeightOnDevice() {
int _StatusBarHeight = 0;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
mView.setDrawingCacheEnabled(true);
Bitmap screenShot = Bitmap.createBitmap(mView.getDrawingCache());
mView.setDrawingCacheEnabled(false);
if (screenShot != null) {
int StatusColor = screenShot.getPixel(0, 0);
for (int y = 1; y < (screenShot.getHeight() / 4); y++) {
if (screenShot.getPixel(0, y) != StatusColor) {
_StatusBarHeight = y - 1;
break;
}
}
}
if (_StatusBarHeight == 0) {
_StatusBarHeight = 50; // Set a default in case we don't find a difference
}

Log.d("YOUR_TAG", "Status Bar was measure at "
+ _StatusBarHeight + " pixels");
return _StatusBarHeight;
}

private File getScreenshotFolder() throws IllegalAccessException {
File screenshotsDir;
if (Build.VERSION.SDK_INT >= 21) {
// Use external storage.
screenshotsDir = new File(getExternalStorageDirectory(),
"screenshots");
} else {
// Use internal storage.
screenshotsDir = new File(mContext.getApplicationContext().getFilesDir(),
"screenshots");
}

synchronized (LOCK) {
if (outputNeedsClear) {
deletePath(screenshotsDir);
outputNeedsClear = false;
}
}

File dirClass = new File(screenshotsDir, mClassName);
File dirMethod = new File(dirClass, mMethodName);
createDir(dirMethod);
return dirMethod;
}

private void createDir(File dir) throws IllegalAccessException {
File parent = dir.getParentFile();
if (!parent.exists()) {
createDir(parent);
}
if (!dir.exists() && !dir.mkdirs()) {
throw new IllegalAccessException(
"Unable to create output dir: " + dir.getAbsolutePath());
}
}

private void deletePath(File path) {
if (path.isDirectory() && path.exists()) {
File[] children = path.listFiles();
if (children != null) {
for (File child : children) {
Log.d("YOUR_TAG", "Deleting " + child.getPath());
deletePath(child);
}
}
}
if (!path.delete()) {
// log message here
}
}
}

然后您可以从 ViewAction 或直接从测试用例类调用它:

查看操作类:

class ScreenshotViewAction implements ViewAction {
private final String mClassName;
private final String mMethodName;
private final int mViewId;
private final String mPrefix;

protected ScreenshotViewAction(final int viewId, final String className,
final String methodName, @Nullable final String prefix) {
mViewId = viewId;
mClassName = className;
mMethodName = methodName;
mPrefix = prefix;
}

@Override
public Matcher<View> getConstraints() {
return ViewMatchers.isDisplayed();
}

@Override
public String getDescription() {
return "Taking a screenshot.";
}

@Override
public void perform(final UiController aUiController, final View aView) {
aUiController.loopMainThreadUntilIdle();
final long startTime = System.currentTimeMillis();
final long endTime = startTime + 2000;
final Matcher<View> viewMatcher = ViewMatchers.withId(mViewId);
do {
for (View child : TreeIterables.breadthFirstViewTraversal(aView)) {
// found view with required ID
if (viewMatcher.matches(child)) {
CaptureImage.takeScreenshot(aView.getRootView(), mClassName,
mMethodName, mPrefix);
return;
}
}

aUiController.loopMainThreadForAtLeast(50);
}
while (System.currentTimeMillis() < endTime);
}

现在从您的测试用例类中,创建以下静态方法:

public static void takeScreenshot(int prefix) {
View currentView = ((ViewGroup)mActivity
.getWindow().getDecorView().findViewById(android.R.id.content)).getChildAt(0);
String fullClassName = Thread.currentThread().getStackTrace()[3].getClassName();
String testClassName = fullClassName.substring(fullClassName.lastIndexOf(".") + 1);
String testMethodName = Thread.currentThread().getStackTrace()[3].getMethodName();
CaptureImage.takeScreenshot(currentView, testClassName, testMethodName,
String.valueOf(prefix));
}

public static ViewAction takeScreenshot(@Nullable String prefix) {
String fullClassName = Thread.currentThread().getStackTrace()[3].getClassName();
String className = fullClassName.substring(fullClassName.lastIndexOf(".") + 1);
String methodName = Thread.currentThread().getStackTrace()[3].getMethodName();
return new ScreenshotViewAction(getDecorView().getId(), className, methodName, prefix);
}

或者您可以从执行 View 操作中调用它:

takeScreenshot(0);
onView(withContentDescription(sContext
.getString(R.string.abc_action_bar_up_description)))
.perform(
ScreenshotViewAction.takeScreenshot(String.valueOf(1)),
click()
);

关于java - 编写自定义 Android ViewAction 以截取屏幕截图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28888635/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com