如何为Android测试生成缩放/收缩手势

如何为Android测试生成缩放/收缩手势,android,testing,zooming,gesture,Android,Testing,Zooming,Gesture,我尝试生成缩放/收缩手势进行测试,我尝试使用Android API MotionEvent.Get(),但发现很难实现缩放/收缩事件 我从中引用了API。你能告诉我正确的方法吗 以下是我的实现: //for zoom, we need four points coordinations: start0, start1, end0, end1 Instrumentation inst; // action down event MotionEvent event = MotionEvent.o

我尝试生成缩放/收缩手势进行测试,我尝试使用Android API MotionEvent.Get(),但发现很难实现缩放/收缩事件

我从中引用了API。你能告诉我正确的方法吗

以下是我的实现:

//for zoom, we need four points coordinations: start0, start1, end0, end1

Instrumentation inst;

// action down event
MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, 1, prop_start0, pointerCoords_start0, 0,  0, 0, 0, 0, 0, 0, 0 );
inst.sendPointerSync(event);

// action pointer 2 down event
event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_POINTER_2_DOWN, 2, properties_start0_1, pointerCoords_start0_1, 0, 0, 0, 0, 0, 0, 0, 0);
inst.sendPointerSync(event);

// action move events
duration = 1000; //1000 ms
event_interval = 10;//time interval between consecutive events 10ms 
moveEventNum = duration / event_interval; 
stepx0 = (end0.x - start0.x)/moveEventNum;
stepy0 = (end0.y - start0.y)/moveEventNum;
stepx1 = (end1.x - start1.x)/moveEventNum;
stepy1 = (end1.y - start1.y)/moveEventNum;

move_event0= start0;
move_event1 = start1;
for ( int i = 0; i < moveEventNum; i++) {
       //  [generate middle points here ]
       mov_event0.x += stepx0;
       mov_event0.y += stepy0;
       mov_event1.x += stepx1;
       mov_event1.y += stepy1;

      eventTime += event_interval;

      event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, 2, properties_move_event, pointerCoords_move_event0_1, 0, 0, 0, 0, 0, 0, 0, 0); 

     inst.sendPointerSync(event);
}

event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_POINTER_2_UP, 2, properties_end0_1, pointerCoords_end0_1, 0, 0, 0, 0, 0, 0, 0, 0);
inst.sendPointerSync(event);

event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, 1, end1, pointerCoords_end1, 0, 0, 0, 0, 0, 0, 0, 0 );
inst.sendPointerSync(event);
//对于缩放,我们需要四点坐标:start0、start1、end0、end1
仪器仪表研究所;
//动作停止事件
MotionEvent事件=MotionEvent.Get(停机时间、事件时间、MotionEvent.ACTION\u DOWN、1、prop\u start0、pointerCoords\u start0、0、0、0、0、0);
inst.sendPointerSync(事件);
//动作指针2向下事件
event=MotionEvent.Get(停机时间、事件时间、MotionEvent.ACTION\u指针\u 2\u向下、2、属性\u开始\u 1、指针指针\u开始\u 1、0、0、0、0、0);
inst.sendPointerSync(事件);
//动作移动事件
持续时间=1000//1000毫秒
事件间隔=10//连续事件之间的时间间隔为10ms
moveEventNum=持续时间/事件间隔;
stepx0=(end0.x-start0.x)/moveEventNum;
stepy0=(end0.y-start0.y)/moveEventNum;
stepx1=(end1.x-start1.x)/moveEventNum;
步骤1=(end1.y-start1.y)/moveEventNum;
移动事件0=开始0;
移动事件1=开始1;
for(int i=0;ievent=MotionEvent.get(停机时间、事件时间、MotionEvent.ACTION\u指针\u 2\u向上、2、属性\u end0\u 1、指针指针\u end0\u 1、0、0、0、0);
inst.sendPointerSync(事件);
event=MotionEvent.get(停机时间、事件时间、MotionEvent.ACTION\u UP、1、end1、指针指针指针\u end1、0、0、0、0、0、0);
inst.sendPointerSync(事件);

我发现了问题所在

问题:

使用get()API时,我们必须设置每个事件中点的压力和大小

为了

指针指针指针[],我们必须将压力和大小设置为1,默认值为0

为了

我的手势制作技巧:

1。遵循真实手势序列,因为我们希望模拟真实手势

  • 重写onTouchEvent()以检查接收到的真实事件 应用这些事件还可用于比较真实事件 用户触摸事件和生成的触摸事件以浏览器为例 例如:

    a) @覆盖公共布尔onTouchEvent(MotionEvent事件){ Log.i(“WebView”,event.toString()+event.getAction());布尔rt =super.onTouchEvent(事件);返回rt;}

  • 手动触摸屏以从a)中的onTouchEvent()获取真实手势序列。我们可以在生成事件时遵循事件序列。 --如果我们不遵循手势事件序列,则可能会拒绝插入指令的事件

  • 这是缩放手势的有效事件序列(所有事件的停机时间相同)

    一,。行动(减少一个起点)

    二,。动作\u指针\u 2 \u两个起点向下

    三、两个中点的移动

    iv.两个端点的行动指针

    五,。一个端点的动作

2。正确使用API MotionEvent.Acquire

  • 有两种最常用的获取()API
获取公共静态运动事件(长停机时间、长事件时间、int动作、, 浮点x、浮点y、整数元状态)

获取公共静态MotionEvent(long,long,int,int,android.view.MotionEvent.PointerProperties[], android.view.MotionEvent.PointerCoords[],int,int,float,float,int,int,int,int)

第一个通常用于单点手势,如投掷、滚动、单击等。此功能的参数(压力、大小、xPresion、yPresion)均设置为1

第二个是更通用的,可以用于多点触控事件的生成。而对于第二个,我们必须将每个接触点的压力、大小(以指针为单位)设置为1

以下是生成缩放手势的示例:

public static void generateZoomGesture(仪器仪表),
长起始时间、布尔ifMove、手势信息点起始点1、,
GestureInfo.Point startPoint2,GestureInfo.Point endPoint1,
GestureInfo.Point endPoint2,int duration){
如果(inst==null | | startPoint1==null
||(ifMove&&endPoint1==null)){
返回;
}
长事件时间=开始时间;
长时间停机=开始时间;
运动事件;
浮动事件X1、事件1、事件X2、事件2;
eventX1=起始点1.x;
事件1=起始点1.y;
eventX2=startPoint2.x;
事件2=起始点2.y;
//指定两个接触点的特性
PointerProperties[]属性=新的PointerProperties[2];
PointerProperties pp1=新的PointerProperties();
pp1.id=0;
pp1.toolType=MotionEvent.TOOL\u TYPE\u FINGER;
PointerProperties pp2=新的PointerProperties();
pp2.id=1;
pp2.toolType=MotionEvent.TOOL\u TYPE\u FINGER;
属性[0]=pp1;
性质[1]=pp2;
//指定两个接触点的坐标
//注意:必须设置压力和大小值,否则它将不起作用
PointerCoords[]PointerCoords=新的PointerCoords[2];
PointerCoords pc1=新的PointerCoords();
pc1.x=eventX1;
pc1.y=事件1;
pc1.压力=1;
pc1.size=1;
PointerCoords pc2=新的PointerCoords();
pc2.x=eventX2;
pc2.y=事件2;
pc2.压力=1;
pc2.1尺寸=1;
指针指针指针[0]=pc1;
指针指针指针[1]=pc2;
//////////////////////////////////////////////////
obtain(long, long, int, int, android.view.MotionEvent.PointerProperties[], 
android.view.MotionEvent.PointerCoords[], int, int, float, float, int, int, int, int)
public static MotionEvent obtain (long downTime, long eventTime, int action,
         float x, float y, int metaState)

     Create a new MotionEvent, filling in a subset of the basic motion values. 
    Those not specified here are: device id (always 0), pressure and size (always 1), 
x and y precision (always 1), and edgeFlags (always 0).

since the default pressure and size are 1, so we don't need to set them.
public static void generateZoomGesture(Instrumentation inst,
        long startTime, boolean ifMove, GestureInfo.Point startPoint1,
        GestureInfo.Point startPoint2, GestureInfo.Point endPoint1,
        GestureInfo.Point endPoint2, int duration) {

    if (inst == null || startPoint1 == null
            || (ifMove && endPoint1 == null)) {
        return;
    }

    long eventTime = startTime;
    long downTime = startTime;
    MotionEvent event;
    float eventX1, eventY1, eventX2, eventY2;

    eventX1 = startPoint1.x;
    eventY1 = startPoint1.y;
    eventX2 = startPoint2.x;
    eventY2 = startPoint2.y;

    // specify the property for the two touch points
    PointerProperties[] properties = new PointerProperties[2];
    PointerProperties pp1 = new PointerProperties();
    pp1.id = 0;
    pp1.toolType = MotionEvent.TOOL_TYPE_FINGER;
    PointerProperties pp2 = new PointerProperties();
    pp2.id = 1;
    pp2.toolType = MotionEvent.TOOL_TYPE_FINGER;

    properties[0] = pp1;
    properties[1] = pp2;

    //specify the coordinations of the two touch points
    //NOTE: you MUST set the pressure and size value, or it doesn't work
    PointerCoords[] pointerCoords = new PointerCoords[2];
    PointerCoords pc1 = new PointerCoords();
    pc1.x = eventX1;
    pc1.y = eventY1;
    pc1.pressure = 1;
    pc1.size = 1;
    PointerCoords pc2 = new PointerCoords();
    pc2.x = eventX2;
    pc2.y = eventY2;
    pc2.pressure = 1;
    pc2.size = 1;
    pointerCoords[0] = pc1;
    pointerCoords[1] = pc2;

    //////////////////////////////////////////////////////////////
    // events sequence of zoom gesture
    // 1. send ACTION_DOWN event of one start point
    // 2. send ACTION_POINTER_2_DOWN of two start points
    // 3. send ACTION_MOVE of two middle points
    // 4. repeat step 3 with updated middle points (x,y),
    //      until reach the end points
    // 5. send ACTION_POINTER_2_UP of two end points
    // 6. send ACTION_UP of one end point
    //////////////////////////////////////////////////////////////

    // step 1
    event = MotionEvent.obtain(downTime, eventTime, 
                MotionEvent.ACTION_DOWN, 1, properties, 
                pointerCoords, 0,  0, 1, 1, 0, 0, 0, 0 );

    inst.sendPointerSync(event);

    //step 2
    event = MotionEvent.obtain(downTime, eventTime, 
                MotionEvent.ACTION_POINTER_2_DOWN, 2, 
                properties, pointerCoords, 0, 0, 1, 1, 0, 0, 0, 0);

    inst.sendPointerSync(event);

    //step 3, 4
    if (ifMove) {
        int moveEventNumber = 1;
        moveEventNumber = duration / EVENT_MIN_INTERVAL;

        float stepX1, stepY1, stepX2, stepY2;

        stepX1 = (endPoint1.x - startPoint1.x) / moveEventNumber;
        stepY1 = (endPoint1.y - startPoint1.y) / moveEventNumber;
        stepX2 = (endPoint2.x - startPoint2.x) / moveEventNumber;
        stepY2 = (endPoint2.y - startPoint2.y) / moveEventNumber;

        for (int i = 0; i < moveEventNumber; i++) {
            // update the move events
            eventTime += EVENT_MIN_INTERVAL;
            eventX1 += stepX1;
            eventY1 += stepY1;
            eventX2 += stepX2;
            eventY2 += stepY2;

            pc1.x = eventX1;
            pc1.y = eventY1;
            pc2.x = eventX2;
            pc2.y = eventY2;

            pointerCoords[0] = pc1;
            pointerCoords[1] = pc2;

            event = MotionEvent.obtain(downTime, eventTime,
                        MotionEvent.ACTION_MOVE, 2, properties, 
                        pointerCoords, 0, 0, 1, 1, 0, 0, 0, 0);

            inst.sendPointerSync(event);
        }
    }

    //step 5
    pc1.x = endPoint1.x;
    pc1.y = endPoint1.y;
    pc2.x = endPoint2.x;
    pc2.y = endPoint2.y;
    pointerCoords[0] = pc1;
    pointerCoords[1] = pc2;

    eventTime += EVENT_MIN_INTERVAL;
    event = MotionEvent.obtain(downTime, eventTime,
                MotionEvent.ACTION_POINTER_2_UP, 2, properties, 
                pointerCoords, 0, 0, 1, 1, 0, 0, 0, 0);
    inst.sendPointerSync(event);

    // step 6
    eventTime += EVENT_MIN_INTERVAL;
    event = MotionEvent.obtain(downTime, eventTime, 
                MotionEvent.ACTION_UP, 1, properties, 
                pointerCoords, 0, 0, 1, 1, 0, 0, 0, 0 );
    inst.sendPointerSync(event);
}
// Pinch out (to zoom in):
onView(withId(R.id.MyViewId)).perform(pinchOut());
public static ViewAction pinchOut() {
    return new ViewAction() {
        @Override
        public Matcher<View> getConstraints() {
            return ViewMatchers.isEnabled();
        }

        @Override
        public String getDescription() {
            return "Pinch out";
        }

        @Override
        public void perform(UiController uiController, View view) {
            Point middlePosition = getCenterPoint(view);

            final int startDelta = 0; // How far from the center point each finger should start
            final int endDelta = 500; // How far from the center point each finger should end (note: Be sure to have this large enough so that the gesture is recognized!)

            Point startPoint1 = new Point(middlePosition.x - startDelta, middlePosition.y);
            Point startPoint2 = new Point(middlePosition.x + startDelta, middlePosition.y);
            Point endPoint1 = new Point(middlePosition.x - endDelta, middlePosition.y);
            Point endPoint2 = new Point(middlePosition.x + endDelta, middlePosition.y);

            performPinch(uiController, startPoint1, startPoint2, endPoint1, endPoint2);
        }
    };
}

public static ViewAction pinchIn() {
    return new ViewAction() {
        @Override
        public Matcher<View> getConstraints() {
            return ViewMatchers.isEnabled();
        }

        @Override
        public String getDescription() {
            return "Pinch in";
        }

        @Override
        public void perform(UiController uiController, View view) {
            Point middlePosition = getCenterPoint(view);

            final int startDelta = 500; // How far from the center point each finger should start (note: Be sure to have this large enough so that the gesture is recognized!)
            final int endDelta = 0; // How far from the center point each finger should end

            Point startPoint1 = new Point(middlePosition.x - startDelta, middlePosition.y);
            Point startPoint2 = new Point(middlePosition.x + startDelta, middlePosition.y);
            Point endPoint1 = new Point(middlePosition.x - endDelta, middlePosition.y);
            Point endPoint2 = new Point(middlePosition.x + endDelta, middlePosition.y);

            performPinch(uiController, startPoint1, startPoint2, endPoint1, endPoint2);
        }
    };
}

@NonNull
private static Point getCenterPoint(View view) {
    int[] locationOnScreen = new int[2];
    view.getLocationOnScreen(locationOnScreen);
    float viewHeight = view.getHeight() * view.getScaleY();
    float viewWidth = view.getWidth() * view.getScaleX();
    return new Point(
            (int) (locationOnScreen[0] + viewWidth / 2),
            (int) (locationOnScreen[1] + viewHeight / 2));
}

private static void performPinch(UiController uiController, Point startPoint1, Point startPoint2, Point endPoint1, Point endPoint2) {
    final int duration = 500;
    final long eventMinInterval = 10;
    final long startTime = SystemClock.uptimeMillis();
    long eventTime = startTime;
    MotionEvent event;
    float eventX1, eventY1, eventX2, eventY2;

    eventX1 = startPoint1.x;
    eventY1 = startPoint1.y;
    eventX2 = startPoint2.x;
    eventY2 = startPoint2.y;

    // Specify the property for the two touch points
    MotionEvent.PointerProperties[] properties = new MotionEvent.PointerProperties[2];
    MotionEvent.PointerProperties pp1 = new MotionEvent.PointerProperties();
    pp1.id = 0;
    pp1.toolType = MotionEvent.TOOL_TYPE_FINGER;
    MotionEvent.PointerProperties pp2 = new MotionEvent.PointerProperties();
    pp2.id = 1;
    pp2.toolType = MotionEvent.TOOL_TYPE_FINGER;

    properties[0] = pp1;
    properties[1] = pp2;

    // Specify the coordinations of the two touch points
    // NOTE: you MUST set the pressure and size value, or it doesn't work
    MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[2];
    MotionEvent.PointerCoords pc1 = new MotionEvent.PointerCoords();
    pc1.x = eventX1;
    pc1.y = eventY1;
    pc1.pressure = 1;
    pc1.size = 1;
    MotionEvent.PointerCoords pc2 = new MotionEvent.PointerCoords();
    pc2.x = eventX2;
    pc2.y = eventY2;
    pc2.pressure = 1;
    pc2.size = 1;
    pointerCoords[0] = pc1;
    pointerCoords[1] = pc2;

    /*
     * Events sequence of zoom gesture:
     *
     * 1. Send ACTION_DOWN event of one start point
     * 2. Send ACTION_POINTER_DOWN of two start points
     * 3. Send ACTION_MOVE of two middle points
     * 4. Repeat step 3 with updated middle points (x,y), until reach the end points
     * 5. Send ACTION_POINTER_UP of two end points
     * 6. Send ACTION_UP of one end point
     */

    try {
        // Step 1
        event = MotionEvent.obtain(startTime, eventTime,
                MotionEvent.ACTION_DOWN, 1, properties,
                pointerCoords, 0, 0, 1, 1, 0, 0, 0, 0);
        injectMotionEventToUiController(uiController, event);

        // Step 2
        event = MotionEvent.obtain(startTime, eventTime,
                MotionEvent.ACTION_POINTER_DOWN + (pp2.id << MotionEvent.ACTION_POINTER_INDEX_SHIFT), 2,
                properties, pointerCoords, 0, 0, 1, 1, 0, 0, 0, 0);
        injectMotionEventToUiController(uiController, event);

        // Step 3, 4
        long moveEventNumber = duration / eventMinInterval;

        float stepX1, stepY1, stepX2, stepY2;

        stepX1 = (endPoint1.x - startPoint1.x) / moveEventNumber;
        stepY1 = (endPoint1.y - startPoint1.y) / moveEventNumber;
        stepX2 = (endPoint2.x - startPoint2.x) / moveEventNumber;
        stepY2 = (endPoint2.y - startPoint2.y) / moveEventNumber;

        for (int i = 0; i < moveEventNumber; i++) {
            // Update the move events
            eventTime += eventMinInterval;
            eventX1 += stepX1;
            eventY1 += stepY1;
            eventX2 += stepX2;
            eventY2 += stepY2;

            pc1.x = eventX1;
            pc1.y = eventY1;
            pc2.x = eventX2;
            pc2.y = eventY2;

            pointerCoords[0] = pc1;
            pointerCoords[1] = pc2;

            event = MotionEvent.obtain(startTime, eventTime,
                    MotionEvent.ACTION_MOVE, 2, properties,
                    pointerCoords, 0, 0, 1, 1, 0, 0, 0, 0);
            injectMotionEventToUiController(uiController, event);
        }

        // Step 5
        pc1.x = endPoint1.x;
        pc1.y = endPoint1.y;
        pc2.x = endPoint2.x;
        pc2.y = endPoint2.y;
        pointerCoords[0] = pc1;
        pointerCoords[1] = pc2;

        eventTime += eventMinInterval;
        event = MotionEvent.obtain(startTime, eventTime,
                MotionEvent.ACTION_POINTER_UP + (pp2.id << MotionEvent.ACTION_POINTER_INDEX_SHIFT), 2, properties,
                pointerCoords, 0, 0, 1, 1, 0, 0, 0, 0);
        injectMotionEventToUiController(uiController, event);

        // Step 6
        eventTime += eventMinInterval;
        event = MotionEvent.obtain(startTime, eventTime,
                MotionEvent.ACTION_UP, 1, properties,
                pointerCoords, 0, 0, 1, 1, 0, 0, 0, 0);
        injectMotionEventToUiController(uiController, event);
    } catch (InjectEventSecurityException e) {
        throw new RuntimeException("Could not perform pinch", e);
    }
}

/**
 * Safely call uiController.injectMotionEvent(event): Detect any error and "convert" it to an
 * IllegalStateException
 */
private static void injectMotionEventToUiController(UiController uiController, MotionEvent event) throws InjectEventSecurityException {
    boolean injectEventSucceeded = uiController.injectMotionEvent(event);
    if (!injectEventSucceeded) {
        throw new IllegalStateException("Error performing event " + event);
    }
}