毕设每日工作
Posted axin-
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了毕设每日工作相关的知识,希望对你有一定的参考价值。
android导出已安装应用程序apk文件(命令行模式)
参考文章
1.列出当前手机上已经安装的apk:
adb shell pm list packages
2.找到想要提取的apk存放路径:
adb shell pm path com.huawei.camera
3.使用命令: adb pull ,将其导出保存到自己电脑桌面上:
adb pull /system/priv-app/HwCamera2/HwCamera2.apk C:/Users/fly/Desktop
使用pm查看“相册”软件apk包所在位置时,发现有三个包:
对应分别为:主包、分辨率相关包、语言包
测试安卓原生软件:deskclock、photos
deskclock
-
场景一:
录制内容:秒表功能,点击开始计时,10s后点击暂停计时
重放效果:成功点击开始和暂停,但是两次点击之间的时间差不是10s,而是接近12s。这是因为录制重放引入的时间开销
-
场景二:
录制内容:添加一个8:40的闹钟,通过滑动指针位置设定时间,单击确定添加闹钟
重放效果:成功重放
photos
- 测试输入:对图片进行多指缩放
- 使用aoktool解析相册软件photos时,未能解析出软件界面,录制失败
测试安卓多点触控
问题:sara由于应用场景限制,并未实现多指触控。而是重写dispatchTouchEvent方法做单点触控
多点触控录制出的trace.log不正确,尝试采用
处理多点触控手势
在Android中,将屏幕的左上角的顶点作为Android坐标系的原点,这个原点向右是X轴正方向,原点向下是Y轴正方向。如下图所示:
getRawX():获取点击事件距离整个屏幕左边距离,即绝对坐标
getRawY():获取点击事件距离整个屏幕顶边的的距离,即绝对坐标
sara因场景需求,只实现了单点触控,而没有处理多点触控(例如两指缩放操作)
拟将毕设的创新点放在处理多点触控方向,在录制转换重放阶段调整对应代码。
问题:将录制到trace.log的坐标用matplotlib进行轨迹绘制,只能看到一个手指的轨迹。
经过查阅android开发文档,在多点触控处理上通过pointerId、pointerIndex来区分不同的手指触控。
getPointerCount() 获取在屏幕上手指的个数来判断当前是否为多点触控事件。修改api再次测试录制:
可以看到下图中提示**getRawX()**参数个数不匹配
翻阅安卓开发文档,确实是有int类型参数用来区分不手指的坐标。针对此问题还在查阅修改中
4/19-4/25
对于实现多点触控操作,我的思路是将多点触控分离成几个单点触控,然后根据记录的时间同时重放几个单点操作,从而实现多点触控的录制重放。
一、多点触控录制
-
首先要录制下多点触控的轨迹,并将不同手指的轨迹分离到不同的操作序列
-
重写‘dispatchTouchEvent’方法:使用getRawX()、getRawY()获取当前手指触摸位置相对于手机屏幕左上角的位置;但是上周测试getRawX()、getRawY()的有参数调用方式来获取每个手指的坐标,提示参数错误。
-
转换思路,尝试使用getX()、getY()获取手指相对当前操作组件的坐标,然后结合当前操作组件相对于手机左上角的坐标,计算出当前手指触摸位置相对于手机屏幕左上角的位置。实际使用中发现在dispatchTouchEvent方法下,getX()、getY()获取的坐标就是相对于屏幕左上角的(吐槽一下安卓官方开发文档。。。这种特殊情况竟然不标注);测试代码和测试结果如下:
setImmediate(function()
console.log("[*] Starting script");
Java.perform(function()
var activity = Java.use("com.byted.camp.todolist.MainActivity");
activity.dispatchTouchEvent.implementation = function(ev)
var actionId = ev.getAction();
var pointerCount = ev.getPointerCount() ;
for(var i = 0; i < pointerCount; i++)
send(
i: i,
RawX: ev.getRawX(),
RawY: ev.getRawY(),
x: ev.getX(i),
y: ev.getY(i)
);
return this.dispatchTouchEvent(ev);
;
)
console.log("[*] Ending script");
);
- 基于此修改录制滑动操作部分的代码如下:
if(isInstrument)
existsDispatchTouchHandles.push(methodHandle);
activity.dispatchTouchEvent.implementation = function(ev)
var actionId = ev.getActionMasked();
var pointCount = ev.getPointerCount(); //当前Action在操作的手指数
var action = ev.actionToString(actionId);
var timestamp = +new Date()/1000;
for(var i = 0; i < pointCount; ++i)
var x = ev.getX(i);
var y = ev.getY(i);
send(
x: x,
y: y,
actionId: actionId,
action: action,
activity: '' + this,
msgType: 'touchEvent',
target: 'activity',
eventTime: ev.getEventTime(),
downTime: ev.getDownTime(),
deviceId: ev.getDeviceId(),
timestamp: timestamp
);
return this.dispatchTouchEvent(ev);
;
- 一个正常的多点操作序列应当是(中间会有更多的ActionMove)如下所示:
ActionDown
ActionMove
…
ActionMove
ActionPointerDown
ActionMove
…
ActionMove
ActionPointerUp
ActionMove
ActionUp
- 在录制时发现会出现连续重复的ActionPointerDown、ActionPointerUp如下:
ActionDown
ActionMove
…
ActionMove
ActionPointerDown
ActionPointerDown
ActionMove
…
ActionMove
ActionPointerUp
ActionPointerUp
ActionMove
ActionUp
- 经过分析是因为发生副手指按下抬起操作时,本事件包含至少两根手指,简单的遍历所有的手指并都send出其信息导致了ActionPointerDown、ActionPointerUp的连续出现。修改代码如下:
if(isInstrument)
existsDispatchTouchHandles.push(methodHandle);
activity.dispatchTouchEvent.implementation = function(ev)
var actionId = ev.getActionMasked(); //Action的ID:第一个手指按下是0,其余手指按下是5,非最后一根手指抬起是6,最后一根手指抬起是1
var actionIndex = ev.getActionIndex(); //触发当前Action的手指Index
var pointCount = ev.getPointerCount(); //当前Action在操作的手指数
var action = ev.actionToString(actionId);
var timestamp = +new Date()/1000;
for(var i = 0; i < pointCount; ++i)
// 5:ActionPointerDown 6:ActionPointerUp
if((actionId == 5 || actionId == 6) && i != actionIndex)
continue;
var x = ev.getX(i);
var y = ev.getY(i);
send(
x: x,
y: y,
actionId: actionId,
action: action,
activity: '' + this,
msgType: 'touchEvent',
target: 'activity',
eventTime: ev.getEventTime(),
downTime: ev.getDownTime(),
deviceId: ev.getDeviceId(),
timestamp: timestamp
);
return this.dispatchTouchEvent(ev);
;
- 确保录制出的操作序列正确后,对录制的多点触控数据进行绘图,可以看到多点触控的录制没有问题
- 由于此时重放部分还未修改为支持多点触控,因此直接将多点录制内容进行自重播页面抖动
原因是:原本两个手指同时滑动的轨迹会被识别合并到同一个手指的滑动中。
一个需要修改的问题
- 在自重放阶段,测试了一下录制的脚本能否在其他的软件重放。由于录制操作只包含滑动,并不需要对小部件识别。竟然可以在非录制时使用的软件上重放;
- 原因是重放阶段未检查当前显示软件界面是否和录制软件相同。导致在a软件录制的操作可以在b软件重放,会引起一些意外错误核问题;应当在trace_replay.py里uiautomator连接手机之后判断当前屏幕显示的软件是否和录制时相同。
d = u2.connect()
print(d.info)
if d.info['currentPackageName'] != '录制的软件包名':
print('当前应用非录制时应用,请将录制时的软件打开再重放')
print('currentPackageName:', d.info['currentPackageName']) # 测试
- 而trace_replay.py是由parse_event.py调用events_to_action.py生成的,因此应当在生成trace_replay.py时通过字符串替换做上述代码的修改
二、多点触控重放
- 对滑动操作的重放分为几个部分
- 从trace.log中分离出属于滑动操作的条目,转换为滑动点序列
- 去除坐标相同的点
- 计算每两个相邻点按下的时间间隔序列,对序列求中位数计算出重放改滑动的时间
- 生成重放序列并调用uiautomator提供的api进行重放
uiautomator所提供api包含单点滑动和双指缩放,但不能满足多点滑动的需求
- 对几种多指触控重放思路的测试:
import uiautomator2 as u2
import threading
d = u2.connect()
# 1.调用pinch_in、pinch_out实现两指放缩
d(packageName="com.google.android.apps.photos").pinch_in(percent=100, steps=10) # 两指缩小
d(packageName="com.google.android.apps.photos").pinch_out() # 两指放大
# 2.调用gesture实现两指操作,实际测试中发现,两指操作会进行坐标上的相互抵消,并不能正确执行两指操作。猜测该api可能被废弃
d().gesture((300, 500), (300, 900), (300, 900), (300, 200), 10)
# 3.开两个线程同时执行单指下滑和单指上滑,实际执行出现快速地抖动,应该也是把两个指头的滑动合并成一个手指滑动导致的
def down(d):
d.swipe(300, 500, 300, 700)
def up(d):
d.swipe(300, 900, 300, 700)
t1 = threading.Thread(target=down, args=(u2.connect(),))
t2 = threading.Thread(target=up, args=(u2.connect(),))
t1.start()
t2.start()
t1.join()
t2.join()
# 4.查到uiautomator的多点触控api,但python并没有对该方法进行封装,不理解应该怎么在python中加入对java的借口调用,应该要修改uiautomator实现
# boolean performMultiPointerGesture(PointerCoords...touches)
# boolean performTwoPointerGesture(PointstartPoint1, Point startPoint2, Point endPoint1, Point endPoint2, int steps)
getevent/sendevent
getevent命令得到的事件类型五元组:timestamp、device、type、code、value
timestamp | device | type | code | value |
---|---|---|---|---|
时间戳 | 输入设备 | 类型 | 编号 | 值 |
16bits | 16bits | 32bits |
(其中timestamp表是从上次系统重新启动以来经过的时间。example:40-719451 即 40
seconds and 719,451 microseconds)
- 通过getevent录制操作数据并修改格式存储到recordedEvents.txt
adb shell getevent -t > recordedEvents.txt
cat recordedEvents.txt | sed 's/[][]//g' | sed 's/ //' | awk 'if($1~/[0-9]/)print' > recordedEvents.txt
- 使用翻译程序将recordedEvents.txt转换为标准格式的 translatedEvents.txt
java -jar Translate.jar recordedEvents.txt translatedEvents.txt
timestamp 时间戳
eventNumber 输入设备号
- 用sendevent实现单点滑动事件:
- 三条sendevent语句代表
ActionDown
sendevent /dev/input/event0 3 57 1 sendevent /dev/input/event0 1 330 1 sendevent /dev/input/event0 1 325 1
- 每三条语句代表一个
ActionMove
,循环多次实现滑动过程
sendevent /dev/input/event0 3 53 x sendevent /dev/input/event0 3 54 y sendevent /dev/input/event0 0 0 0
- 四条sendevent语句代表
ActionUp
sendevent /dev/input/event0 3 57 4294967295 sendevent /dev/input/event0 1 330 0 sendevent /dev/input/event0 1 325 0 sendevent /dev/input/event0 0 0 0
- 三条sendevent语句代表
public static void swipeStart()
sendEvent(EV_ABS, ABS_MT_TRACKING_ID, parseTrackingId());
sendEvent(EV_KEY, BTN_TOUCH, PRESS_DOWN);
sendEvent(EV_KEY, BTN_TOOL_FINGER, PRESS_DOWN);
private static final int SWIPE_RUN_INTERVAL = 50;
public static void swipeRun(int x1, int y1, int x2, int y2)
// TODO: emulate touch press 3-0x30 3-0x31
int xStep = (x2 - x1) / SWIPE_RUN_INTERVAL;
int yStep = (y2 - y1) / SWIPE_RUN_INTERVAL;
int x = x1, y = y1;
for (int step = 0; step <= SWIPE_RUN_INTERVAL; ++step)
sendEvent(EV_ABS, ABS_MT_POSITION_X, x);
sendEvent(EV_ABS, ABS_MT_POSITION_Y, y);
sendEvent(EV_SYN, SYN_REPORT, 0);
x += xStep;
y += yStep;
public static void swipeEnd()
sendEvent(EV_ABS, ABS_MT_TRACKING_ID, TRACKING_END);
sendEvent(EV_KEY, BTN_TOUCH, PRESS_UP);
sendEvent(EV_KEY, BTN_TOOL_FINGER, PRESS_UP);
sendEvent(EV_SYN, SYN_REPORT, 0);
public static final int EV_ABS = 0x03;
public static final int ABS_MT_TRACKING_ID = 0x39 /* Unique ID of initiated contact */;
public static final int EV_KEY = 0x01;
public static final int BTN_TOUCH = 0x14a; // 1:按下 0:释放
public static final int PRESS_DOWN = 1;
public static final int PRESS_UP = 0;
public static final int BTN_TOOL_FINGER = 0x145;
public static final int ABS_MT_POSITION_X = 0x35 /* Center X touch position */;
public static final int ABS_MT_POSITION_Y = 0x36 /* Center Y touch position */;
public static final int EV_SYN = 0x00;
public static final int SYN_REPORT = 0;
public static final int TRACKING_END = 0xFFFFFFFF;
public static final int ABS_MT_SLOT = 0x2F;
关键字解释
ABS_MT_POSITION_X: (必须) 报告触碰的X坐标。
ABS_MT_POSITION_Y: (必须) 报告触碰的Y坐标。
ABS_MT_PRESSURE: (可选) 报告触碰的压力大小或者信号强度。
ABS_MT_TOUCH_MAJOR: (可选) 报告触碰的代表性区域, 或者触碰的最长的尺寸。
ABS_MT_TOUCH_MINOR: (可选) 报告触碰的最小的尺寸。 如果ABS_MT_TOUCH_MAJOR报告的是区域测量,则不使用。
ABS_MT_WIDTH_MAJOR: (可选) 报告触碰本身的代表性区域,或者触碰本身的最大尺寸。 如果触碰的尺寸不知道则不使用。
ABS_MT_WIDTH_MINOR: (可选) 报告触碰本身的最小尺寸。 如果触碰的尺寸不知道则不使用。
ABS_MT_ORIENTATION: (可选) 报告触碰的方向。
ABS_MT_DISTANCE: (可选) 报告触碰本身和表面的距离。
ABS_MT_TOOL_TYPE: (可选) 报告触碰是MT_TOOL_FINGER还是MT_TOOL_PEN.
ABS_MT_TRACKING_ID: (可选) 报告触碰的跟踪ID。跟踪ID是一个非负的任意整数,用来分辨多个同时的操作。例如,当多个手指触碰设备,在手指还在屏幕上时每个手指绑定一个独立的跟踪ID,当手指离开屏幕后,跟踪ID可能被重新使用。
ABS_MT_SLOT: (可选) 报告触碰的slot ID
- 用sendevent实现多点滑动事件:
- 第一个点按下
ActionDown
(Id用来区分不同的手指,但是不同于ActionPointerId,只需要保证不同手指的Id不同即可)
[ 1013350.243534] /dev/input/event3: EV_ABS ABS_MT_TRACKING_ID 000007ee [ 1013350.243534] /dev/input/event3: EV_ABS ABS_MT_POSITION_X 00000186 [ 1013350.243534] /dev/input/event3: EV_ABS ABS_MT_POSITION_Y 00000373 [ 1013350.243534] /dev/input/event3: EV_SYN SYN_REPORT 00000000
sendevent /dev/input/event3 3 57 id sendevent /dev/input/event3 3 53 x sendevent /dev/input/event3 3 54 y sendevent /dev/input/event3 0 0 0
- 非第一个点按下
ActionPointerDown
[ 1013350.250811] /dev/input/event3: EV_ABS ABS_MT_SLOT 00000001 [ 1013350.250811] /dev/input/event3: EV_ABS ABS_MT_TRACKING_ID 000007ef [ 1013350.250811] /dev/input/event3: EV_ABS ABS_MT_POSITION_X 00000250 [ 1013350.250811] /dev/input/event3: EV_ABS ABS_MT_POSITION_Y 00000323 [ 1013350.250811] /dev/input/event3: EV_SYN SYN_REPORT 00000000
sendevent /dev/input/event3 3 ABS_MT_SLOT ActionPointerId sendevent /dev/input/event3 3 57 id sendevent /dev/input/event3 3 53 x sendevent /dev/input/event3 3 54 y sendevent /dev/input/event3 0 0 0
- 通过PointerId上传一个手指当前座标
ActionMove
[ 1013350.377097] /dev/input/event3: EV_ABS ABS_MT_SLOT 00000001 [ 1013350.377097] /dev/input/event3: EV_ABS ABS_MT_POSITION_X 00000250 [ 1013350.377097] /dev/input/event3: EV_ABS ABS_MT_POSITION_Y 0000030b [ 1013350.377097] /dev/input/event3: EV_SYN SYN_REPORT 00000000
sendevent /dev/input/event3 3 ABS_MT_SLOT ActionPointerId sendevent /dev/input/event3 3 53 x sendevent /dev/input/event3 3 54 y sendevent /dev/input/event3 0 0 0
- 非最后一个手指抬起
ActionPointerUp
[ 1013352.660250] /dev/input/event3: EV_ABS ABS_MT_SLOT 00000001 [ 1013352.660250] /dev/input/event3: EV_ABS ABS_MT_TRACKING_ID ffffffff [ 1013352.660250] /dev/input/event3: EV_SYN SYN_REPORT 00000000
sendevent /dev/input/event3 3 ABS_MT_SLOT id sendevent /dev/input/event3 3 57 4294967295 sendevent /dev/input/event3 0 0 0
- 最后一个手指抬起
ActionUp
?
[ 1013354.884143] /dev/input/event3: EV_ABS ABS_MT_TRACKING_ID ffffffff [ 1013354.884143] /dev/input/event3: EV_SYN SYN_REPORT 00000000
sendevent /dev/input/event0 3 57 4294967295 sendevent /dev/input/event0 1 330 0 sendevent /dev/input/event0 1 325 0 sendevent /dev/input/event0 0 0 0
- 第一个点按下
以上是关于毕设每日工作的主要内容,如果未能解决你的问题,请参考以下文章
每日随笔手指训练 ( 手指训练作用 | 哪些人需要手指训练 | 手指操 | 手指康复训练器材 )