Android基础 模拟多点触摸

我的Uiautomator系列的博客中,没有向其他工具一样介绍源码分析的部分,原因是实在太忙,没时间去细看,草草了事分享给大家又怕把大家带入误区,刚好这里我就简单的说说。首先要下载的同学可以点击这里下载。

image

下载后我们可以在 ..\uiautomator\core\com\android\uiautomator\core 的路径下看到这些代码。

通过仔细的寻找,在** InteractionController.java** 文件中找到了一个看起来很好用的一个方法 performMultiPointerGesture :

/** * Performs a multi-touch gesture
 *
 * Takes a series of touch coordinates for at least 2 pointers. Each pointer must have
 * all of its touch steps defined in an array of {@link PointerCoords}. By having the ability
 * to specify the touch points along the path of a pointer, the caller is able to specify
 * complex gestures like circles, irregular shapes etc, where each pointer may take a
 * different path.
 *
 * To create a single point on a pointer's touch path
 * <code>
 *       PointerCoords p = new PointerCoords();
 *       p.x = stepX;
 *       p.y = stepY;
 *       p.pressure = 1;
 *       p.size = 1;
 * </code>
 * @param touches each array of {@link PointerCoords} constitute a single pointer's touch path.
 *        Multiple {@link PointerCoords} arrays constitute multiple pointers, each with its own
 *        path. Each {@link PointerCoords} in an array constitute a point on a pointer's path.
 * @return <code>true</code> if all points on all paths are injected successfully, <code>false
 *        </code>otherwise
 * @since API Level 18 */
public boolean performMultiPointerGesture(PointerCoords[] ... touches) { boolean ret = true; if (touches.length < 2) { throw new IllegalArgumentException("Must provide coordinates for at least 2 pointers");
    } // Get the pointer with the max steps to inject.
    int maxSteps = 0; for (int x = 0; x < touches.length; x++)
        maxSteps = (maxSteps < touches[x].length) ? touches[x].length : maxSteps; // specify the properties for each pointer as finger touch
    PointerProperties[] properties = new PointerProperties[touches.length];
    PointerCoords[] pointerCoords = new PointerCoords[touches.length]; for (int x = 0; x < touches.length; x++) {
        PointerProperties prop = new PointerProperties();
        prop.id = x;
        prop.toolType = MotionEvent.TOOL_TYPE_FINGER;
        properties[x] = prop; // for each pointer set the first coordinates for touch down
        pointerCoords[x] = touches[x][0];
    } // Touch down all pointers
    long downTime = SystemClock.uptimeMillis();
    MotionEvent event;
    event = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 1,
            properties, pointerCoords, 0, 0, 1, 1, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
    ret &= injectEventSync(event); for (int x = 1; x < touches.length; x++) {
        event = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(),
                getPointerAction(MotionEvent.ACTION_POINTER_DOWN, x), x + 1, properties,
                pointerCoords, 0, 0, 1, 1, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
        ret &= injectEventSync(event);
    } // Move all pointers
    for (int i = 1; i < maxSteps - 1; i++) { // for each pointer
        for (int x = 0; x < touches.length; x++) { // check if it has coordinates to move
            if (touches[x].length > i)
                pointerCoords[x] = touches[x][i]; else pointerCoords[x] = touches[x][touches[x].length - 1];
        }

        event = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(),
                MotionEvent.ACTION_MOVE, touches.length, properties, pointerCoords, 0, 0, 1, 1, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);

        ret &= injectEventSync(event);
        SystemClock.sleep(MOTION_EVENT_INJECTION_DELAY_MILLIS);
    } // For each pointer get the last coordinates
    for (int x = 0; x < touches.length; x++)
        pointerCoords[x] = touches[x][touches[x].length - 1]; // touch up
    for (int x = 1; x < touches.length; x++) {
        event = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(),
                getPointerAction(MotionEvent.ACTION_POINTER_UP, x), x + 1, properties,
                pointerCoords, 0, 0, 1, 1, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
        ret &= injectEventSync(event);
    }

    Log.i(LOG_TAG, "x " + pointerCoords[0].x); // first to touch down is last up
    event = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, 1,
            properties, pointerCoords, 0, 0, 1, 1, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
    ret &= injectEventSync(event); return ret;
}

对这个方法解释一下吧:模拟一个多触摸的手势。至少两个点进行一系列的触摸操作,每一个滚动轨迹的点集都需要使用在 PointerCoords 数组中实现它所有的步骤,顺着轨迹指针的路径进行模拟触摸,调用者是能够指定进行完成复杂的手势,例如画圈,不规则形状,其中每个点都可以有不同的路径。(解释的我自己都看不下去了)

废话不说了,直接上我的实战代码吧:

private void zoomin() {
    UiDevice mdevice = getUiDevice();
    int h = mdevice.getDisplayHeight();
    int w = mdevice.getDisplayWidth();
    System.out.println("h: " + h + " w: " + w);

    MultiPointerGesture(w / 2 - 100, h / 2 - 100, w / 2 + 100, h / 2 + 100);
}

private void MultiPointerGesture(int x1, int y1, int x2, int y2) {
    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;

    PointerCoords[] pointerCoords = new PointerCoords[2];
    PointerCoords pc1 = new PointerCoords();
    pc1.pressure = 1;
    pc1.size = 1;
    pc1.x = x1;
    pc1.y = y1;
    PointerCoords pc2 = new PointerCoords();
    pc2.pressure = 1;
    pc2.size = 1;
    pc2.x = x1;
    pc2.y = y1;
    pointerCoords[0] = pc1;
    pointerCoords[1] = pc2;

    PointerProperties[] properties2 = new PointerProperties[2];
    PointerProperties pp12 = new PointerProperties();
    pp12.id = 0;
    pp12.toolType = MotionEvent.TOOL_TYPE_FINGER;
    PointerProperties pp22 = new PointerProperties();
    pp22.id = 1;
    pp22.toolType = MotionEvent.TOOL_TYPE_FINGER;
    properties2[0] = pp12;
    properties2[1] = pp22;

    PointerCoords[] pointerCoords2 = new PointerCoords[2];
    PointerCoords pc12 = new PointerCoords();
    pc12.pressure = 1;
    pc12.size = 1;
    pc12.x = x2;
    pc12.y = y2;
    PointerCoords pc22 = new PointerCoords();
    pc22.pressure = 1;
    pc22.size = 1;
    pc22.x = x2;
    pc22.y = y2;
    pointerCoords2[0] = pc12;
    pointerCoords2[1] = pc22;

    PointerCoords[][] ppCoords = new PointerCoords[2][];
    ppCoords[0] = pointerCoords;
    ppCoords[1] = pointerCoords2;

    UiDevice device = UiDevice.getInstance();

    Class UiDevice_class = UiDevice.class;
    Field field_UiD;
    try
    {
        field_UiD = UiDevice_class.getDeclaredField("mUiAutomationBridge");
        field_UiD.setAccessible(true);
        Object uiAutomatorBridge;

        uiAutomatorBridge = field_UiD.get(device);

        Class tmp = Class.forName("com.android.uiautomator.core.UiAutomatorBridge");
        Field field = tmp.getDeclaredField("mInteractionController");
        field.setAccessible(true);
        Object interactionController = field.get(uiAutomatorBridge);

        Class ijClass = interactionController.getClass();
        Method method = null;
        try
        {
            method = ijClass.getDeclaredMethod("performMultiPointerGesture", new Class[] { PointerCoords[][].class });
        } catch (NoSuchMethodException e)
        {
            // method =
            // ijClass.getDeclaredMethod("performMultiPointerGesture", new
            // Class[]{PointerCoords[].class);
        }
        method.setAccessible(true);
        method.invoke(interactionController, new Object[] { ppCoords });

    } catch (NoSuchFieldException e)
    {
        e.printStackTrace();
    } catch (SecurityException e)
    {
        e.printStackTrace();
    } catch (IllegalArgumentException e)
    {
        e.printStackTrace();
    } catch (IllegalAccessException e)
    {
        e.printStackTrace();
    } catch (InvocationTargetException e)
    {
        e.printStackTrace();
    } catch (ClassNotFoundException e1)
    {
        e1.printStackTrace();
    }
}

可以看到当时花了很大的代价,都用到了反射机制,最终发现Uiautomator对外暴露了这个接口,真是让人哭笑不得啊。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值