我正在做一个通用的自动化脚本。
我需要将复杂的滑动事件发送到 android 屏幕,而无需专门访问重点应用程序
到目前为止,我认为最好的方法是使用 adb,使用 sendevent 命令创建一个文件,将其推送到设备上并从那里运行。即便如此,它还是慢得令人痛苦(与我用 getevent 记录它并将其通过管道传回相比要慢得多)。
我设法优化了文件,因为我发现每个 sendevent block 并不特别需要 X 和 Y,但它仍然慢了几个数量级
部分文件示例(我正在尝试使用 HTC One):
sendevent /dev/input/event5 3 57 49
sendevent /dev/input/event5 3 53 942
sendevent /dev/input/event5 3 54 2747
sendevent /dev/input/event5 0 0 0
sendevent /dev/input/event5 3 53 1207
sendevent /dev/input/event5 3 54 2483
sendevent /dev/input/event5 0 0 0
sendevent /dev/input/event5 3 53 1472
sendevent /dev/input/event5 0 0 0
sendevent /dev/input/event5 3 54 2218
sendevent /dev/input/event5 0 0 0
sendevent /dev/input/event5 3 53 1207
sendevent /dev/input/event5 3 54 2483
sendevent /dev/input/event5 0 0 0
sendevent /dev/input/event5 3 53 1472
所以我的重点是优化单个长而复杂的滑动的速度,而不是多个小滑动的速度。
有人知道更好的方法吗?
因此,Chris Stratton 的想法原则上可行(重新管道化 cat-ed 输出成功生成相同的滑动),但我无法创建自己的代码以将其重新管道化。我猜它是与发送事件命令之间的分隔符有关......但我仍然无法让它工作
我使用了对 sendevent.c 文件的修改来获取每行包含三元组的文件并输出到另一个文件。你碰巧知道可能是什么问题吗?转换看起来不错......
解决方案:我设法解决了它,主要归功于下面的答案。这是一个 C 脚本,它获取一个包含十六进制值的文件并输出适当的二进制文件。
用法:(对我来说,触摸驱动程序文件是/dev/input/event5 - HTC One - 对于其他设备,它可能是不同的文件!!!)
$> adb shell getevent > tmp.in
$> ./sendevent tmp.in tmp.out
$> adb shell push tmp.out /mnt/sdcard/
$> adb shell "cd /mnt/sdcard/ && cat tmp.out > /dev/input/event5"
和来源:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <errno.h>
typedef uint32_t __u32;
typedef uint16_t __u16;
typedef __signed__ int __s32;
__attribute__((aligned(1),packed)) struct input_event {
__u32 time_dummy_1;
__u32 time_dummy_2;
__u16 type;
__u16 code;
__s32 value;
};
int convert (char * str) {
return (int) strtol(str, NULL, 16);
}
#define S_ALL (S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH)
int main (int argc, char *argv[]) {
int i;
int fd;
int ret;
if(argc < 3) {
fprintf(stderr, "use: %s in-file out-file\n", argv[0]);
return 1;
}
fd = open(argv[2], O_CREAT | O_WRONLY, S_ALL);
if(fd < 0) {
fprintf(stderr, "could not open %s, %s\n", argv[2], strerror(errno));
return 1;
}
FILE * fd_in = fopen(argv[1], "r");
if (fd_in == NULL) {
fprintf(stderr, "Can't open input file: %s\n", argv[1]);
return 1;
}
struct input_event event;
char type[32];
char code[32];
char value[32];
int count = 0;
while (fscanf(fd_in, "%s %s %s", type, code, value) != EOF) {
memset(&event, 0, sizeof(event));
// printf("%d) %s %s %s\n", ++count, type, code, value);
event.type = convert(type);
event.code = convert(code);
event.value = convert(value);
memset(type, 0, sizeof(type));
memset(code, 0, sizeof(code));
memset(value, 0, sizeof(value));
ret = write(fd, &event, sizeof(event));
if(ret < sizeof(event)) {
fprintf(stderr, "write event failed, %s\n", strerror(errno));
return -1;
}
}
return 0;
}
最佳答案
请注意,此答案适用于 2013 年左右的 Android 版本,可能不适用于当前版本。当时 Jellybean 是当代的,Kitkat 在问题被提出几周后问世
您的延迟可能是由于必须重复启动新的 sendevent 进程、解析文本事件记录并打开设备节点而导致的低效 - 对于每个单独的事件。如果您改为在单个进程中执行所有操作,只打开设备文件一次,效率会高得多。
如果我们在工具箱中查看 sendevent 的来源与问题的日期同时(例如,https://android.googlesource.com/platform/system/core/+/jb-release/toolbox/sendevent.c),我们会看到它正在做的事情的核心是将事件编码成二进制记录
struct input_event {
struct timeval time;
__u16 type;
__u16 code;
__s32 value;
};
并将它们写入适当的设备
memset(&event, 0, sizeof(event));
event.type = atoi(argv[2]);
event.code = atoi(argv[3]);
event.value = atoi(argv[4]);
ret = write(fd, &event, sizeof(event));
假设你正在执行一些作为 shell userid 或 input unix 组中的其他人,你应该能够完成与 sendevent 从您自己的自定义程序或使用其他命令行工具(如 cat)执行,从而有效地推送事件记录的二进制文件。
例如
adb shell
cd /mnt/sdcard
cat /dev/input/event2 > events
做一些触屏事件,然后ctrl-C杀死猫
现在您可以回放捕获的二进制事件文件:
cat events > /dev/input/event2
(注意:sendevent 将每条记录的 timeval 部分归零;录制和回放可能不会这样做;您必须看到,如果它重要,则将每条记录的那些部分归零在你写回文件之前)
关于Android模拟快速滑动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19063057/
是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou
最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路
假设我在Store的模型中有这个非常简单的方法:defgeocode_addressloc=Store.geocode(address)self.lat=loc.latself.lng=loc.lngend如果我想编写一些不受地理编码服务影响的测试脚本,这些脚本可能已关闭、有限制或取决于我的互联网连接,我该如何模拟地理编码服务?如果我可以将地理编码对象传递到该方法中,那将很容易,但我不知道在这种情况下该怎么做。谢谢!特里斯坦 最佳答案 使用内置模拟和stub的rspecs,你可以做这样的事情:setupdo@subject=MyCl
在ruby中,你可以这样做:classThingpublicdeff1puts"f1"endprivatedeff2puts"f2"endpublicdeff3puts"f3"endprivatedeff4puts"f4"endend现在f1和f3是公共(public)的,f2和f4是私有(private)的。内部发生了什么,允许您调用一个类方法,然后更改方法定义?我怎样才能实现相同的功能(表面上是创建我自己的java之类的注释)例如...classThingfundeff1puts"hey"endnotfundeff2puts"hey"endendfun和notfun将更改以下函数定
我有一个gem,它有一个根据Rails.env的不同行为的方法:defself.envifdefined?(Rails)Rails.envelsif...现在我想编写一个规范来测试这个代码路径。目前我是这样做的:Kernel.const_set(:Rails,nil)Rails.should_receive(:env).and_return('production')...没关系,只是感觉很丑。另一种方法是在spec_helper中声明:moduleRails;end而且效果也很好。但也许有更好的方法?理想情况下,这应该有效:rails=double('Rails')rails.sho
有没有办法快速将表格格式的ruby哈希打印到文件中?如:keyAkeyBkeyC...1232343451253474456...其中散列的值是不同大小的数组。还是使用双循环是唯一的方法?谢谢 最佳答案 试试我写的这个gem(在表中打印散列、ruby对象、ActiveRecord对象):http://github.com/arches/table_print 关于ruby-如何以表格格式快速打印Ruby哈希值?,我们在StackOverflow上找到一个类似的问题:
我有一个rspec模拟对象,一个值赋给了属性。我正在努力在我的rspec测试中满足这种期望。只是想知道语法是什么?代码:defcreate@new_campaign=AdCampaign.new(params[:new_campaign])@new_campaign.creationDate="#{Time.now.year}/#{Time.now.mon}/#{Time.now.day}"if@new_campaign.saveflash[:status]="Success"elseflash[:status]="Failed"endend测试it"shouldabletocreat
我正在尝试测试命令行工具的输出。如何使用rspec来“伪造”命令行调用?执行以下操作不起作用:it"shouldcallthecommandlineandreturn'text'"do@p=Pig.new@p.should_receive(:run).with('my_command_line_tool_call').and_return('resulttext')end如何创建stub? 最佳答案 使用newmessageexpectationsyntax:规范/虚拟规范.rbrequire"dummy"describeDummy
电脑启动出现显示器黑屏是一个相当常见的问题。如果您遇到了这个问题,不要惊慌,因为它有很多可能的原因,可以采取一些简单的措施来解决它。在本文中,小编将介绍下面4种常见的电脑启动后显示器黑屏的原因,排查这些原因,快速解决! 演示机型:联想Ideapad700-15ISK-ISE系统版本:Windows10一、显示器问题如果出现电脑启动后显示器黑屏的情况。那么首先您需要检查一下显示器是否正常工作。您可以通过更换另一个显示器或将当前显示器连接到另一台计算机来检查显示器是否存在问题。如果问题仍然存在,那么您可以排除显示器故障的可能性。 二、显卡问题如果您的电脑配备了独立显卡,那么显卡故障也可能是导致电脑
我有一个或多或少这样的场景classAdefinitialize(&block)b=B.new(&block)endend我正在对A类进行单元测试,我想知道B#new是否正在接收传递给A#new的block。我使用Mocha作为模拟框架。这可能吗? 最佳答案 我用Mocha和RSpec都试过了,虽然我可以通过测试,但行为不正确。从我的实验中,我得出结论,验证block是否已通过是不可能的。问题:为什么要传递一个block作为参数?block将用于什么目的?什么时候调用?也许这确实是您应该用类似的东西测试的行为:classBlockP