毕设每日工作

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包所在位置时,发现有三个包:

对应分别为:主包、分辨率相关包、语言包

App Bundle 开发步骤





测试安卓原生软件:deskclock、photos
deskclock

  • 场景一:
    录制内容:秒表功能,点击开始计时,10s后点击暂停计时
    重放效果:成功点击开始和暂停,但是两次点击之间的时间差不是10s,而是接近12s。这是因为录制重放引入的时间开销

  • 场景二:
    录制内容:添加一个8:40的闹钟,通过滑动指针位置设定时间,单击确定添加闹钟
    重放效果:成功重放

photos

  • 测试输入:对图片进行多指缩放
  • 使用aoktool解析相册软件photos时,未能解析出软件界面,录制失败





测试安卓多点触控
问题:sara由于应用场景限制,并未实现多指触控。而是重写dispatchTouchEvent方法做单点触控
多点触控录制出的trace.log不正确,尝试采用
处理多点触控手势

MotionEvent详解

多点触控详解

android自定义View之多点触控



在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时通过字符串替换做上述代码的修改


二、多点触控重放

  • 对滑动操作的重放分为几个部分
  1. 从trace.log中分离出属于滑动操作的条目,转换为滑动点序列
  2. 去除坐标相同的点
  3. 计算每两个相邻点按下的时间间隔序列,对序列求中位数计算出重放改滑动的时间
  4. 生成重放序列并调用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

timestampdevicetypecodevalue
时间戳输入设备类型编号
16bits16bits32bits

(其中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
    
	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
    

以上是关于毕设每日工作的主要内容,如果未能解决你的问题,请参考以下文章

毕设计划

每日技术 | 毕设

每日随笔手指训练 ( 手指训练作用 | 哪些人需要手指训练 | 手指操 | 手指康复训练器材 )

《寒假每日一题》2022/1/2 AcWing 2058.笨拙的手指

AcWing 1月9日每日一题 2058. 笨拙的手指

AcWing 1月9日每日一题 2058. 笨拙的手指