Instrumentation.sendPointerSync()与MotionEvent.setSource() 模拟按键及事件反控

  Robotium基于Instrumentation的二次封装,然而UiAutomation 也能通过instrumentation.getUiAutomation()拿到。

  android的输入事件处理, 大多跟InputReader, InputManager, InputManagerService。

----  Instrumentation sendPointerSync(MotionEvent event),按键事件
Android Instrumentation模拟鼠标点击事件或按键事件
Instrumentation发送键盘鼠标事件:Instrumentation提供了丰富的以send开头的函数接口来实现模拟键盘鼠标,如下所述:
sendCharacterSync(int keyCode)           //用于发送指定KeyCode的按键
sendKeyDownUpSync(int key)               //用于发送指定KeyCode的按键
sendPointerSync(MotionEvent event)       //用于模拟Touch
sendStringSync(String text)              //用于发送字符串
注意:以上函数必须通过Message的形式抛到Message队列中。如果直接进行调用加会导致程序崩溃。

  Robotium是通过对instrumentation的注入事件(sendKeyDownUpSync、sendPointerSync)的封装、以及通过调用instrumentation的runOnMainSync、runOnUiThread等来完成对控件的操作,让用户可以直接调用一个solo.clickOnText等方法,就能够完成操作,而不用自己去写一堆找到控件,然后再点击触发等方法。
  Android Inputmanager的injectEvent()方法也可以模拟产生输入事件(API16以上版本)。不过此方法属于隐藏方法,需要反射调用。
  Instrumentation mInst = new Instrumentation(); mInst.sendKeyDownUpSync(KeyEvent.KEYCODE_A); //按键事件

这两句. KeyEvent.KEYCODE_A替换成自己的按键需求。
Instrumentation类——Android自动化测试学习历程- https://www.cnblogs.com/keke-xiaoxiami/p/4307571.html

Instrumentation instrument= new Instrumentation(); 
instrumentation.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(),
  SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, dx, dy, 0));
instrumentation.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(),
  SystemClock.uptimeMillis(), MotionEvent.ACTION_MOVE, mx, my, 0));
instrumentation.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(),
  SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, upx, upy, 0));
instrument.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(),  
  SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 200, 300, 0);
instrument.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(), 
  SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, 200, 300, 0);

private static void sendPointerSync(MotionEvent event) {  
    try {  
        (IWindowManager.Stub.asInterface(ServiceManager  
                .getService("window"))).injectPointerEvent(event, true);  
    } catch (RemoteException e) {  
        e.printStackTrace();  
    }  
}  

---- MotionEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN),设置事件源与事件反控
Handler.postDelayed(new Runnable(){
  public void run(){
  event.setSource(InputDevice.SOURCE_TOUCHSCREEN);// 留意参数
  // 同样, 留意参数, 如果参数错, 会不成功.
  imgr.injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
} }, delayed); }

Android——使用InputManager实现模拟滚动- https://blog.csdn.net/weixin_42832981/article/details/89883339
android 模拟发送多点触摸事件- http://www.itgo.me/a/3875849884570322271/InputManager-MotionEvent
Android inject input events 注入Touch 点(x, y) 触摸输入事件- https://blog.csdn.net/zjwfan/article/details/50549784?locationNum=12
1. 使用Instrumentation
new Thread(new Runnable() {
            @Override
            public void run() {
                Instrumentation mInst = new Instrumentation();
                mInst.sendKeyDownUpSync(KeyEvent.KEYCODE_A); //按键事件
                mInst.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMilis(),      
                    SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, point.x, point.y, 0); //触摸按下
                mInst.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMilis(), 
            SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, point.x, point.y, 0); //触摸抬起
                }

}).start();
查看sendPointerSync()方法的源码会看到,它使用的是 injectInputEvent()方法实现:

        public void sendPointerSync(MotionEvent event) {
            validateNotAppThread();
            if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) == 0) {
                event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
            }
            InputManager.getInstance().injectInputEvent(event,
                    InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
        }  
  使用Instrumentation需要<uses-permission android:name="android.permission.INJECT_EVENTS"/>权限,并且跨App注入事件需要系统应用(AndroidManifest.xml 中加入android:sharedUserId="android.uid.system")并且平台签名才行。

2. 使用反射直接调用injectInputEvent() 方法:
    private void invokeInjectInputEvent(MotionEvent event) {
        Class cl = InputManager.class;
        try {
            Method method = cl.getMethod("getInstance");
            Object result = method.invoke(cl);
            InputManager im = (InputManager) result;
            method = cl.getMethod("injectInputEvent", InputEvent.class, int.class);
            method.invoke(im, event, 0);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }  catch (IllegalArgumentException e) {
           e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
4. 针对特定的应用可以使用Android Accessibility
5. 可以直接使用Adb shell
  adb shell input tap point.x point.y
6.monkeyrunner是一个功能更为丰富的选项,不过需要连接电脑

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值